diff --git a/CHANGELOG.MD b/CHANGELOG.MD
index 5b69a06..61b31b5 100644
--- a/CHANGELOG.MD
+++ b/CHANGELOG.MD
@@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
+### [0.1.16] - 2024-04-16
+ - Created nodebase.py for all Node base type for AST1 and AST2 nodes
+ - NodeDataclass/NodeList parenting mechanism added to AST1
+ - Created types.py for shared AST1 and AST2 types
+
### [0.1.15] - 2024-03-20
- Cleaned up AST2 ErrorHandler
- Removed code_errors from AST2Builder, moved to ErrorHandler.caught_errors
diff --git a/example/Aave/interfaces/ITransferHook.sol b/example/Aave/interfaces/ITransferHook.sol
deleted file mode 100644
index 675df13..0000000
--- a/example/Aave/interfaces/ITransferHook.sol
+++ /dev/null
@@ -1,10 +0,0 @@
-// SPDX-License-Identifier: agpl-3.0
-pragma solidity 0.7.5;
-
-interface ITransferHook {
- function onTransfer(
- address from,
- address to,
- uint256 amount
- ) external;
-}
\ No newline at end of file
diff --git a/example/Aave/main/AaveToken.sol b/example/Aave/main/AaveToken.sol
deleted file mode 100644
index 7db8835..0000000
--- a/example/Aave/main/AaveToken.sol
+++ /dev/null
@@ -1,185 +0,0 @@
-// SPDX-License-Identifier: agpl-3.0
-pragma solidity 0.8.10;
-
-import {ERC20} from "../open-zeppelin/ERC20.sol";
-//import {ITransferHook} from "../interfaces/ITransferHook.sol";
-import "../interfaces/ITransferHook.sol";
-import {VersionedInitializable} from "../utils/VersionedInitializable.sol";
-
-
-/**
-* @notice implementation of the AAVE token contract
-* @author Aave
-*/
-contract AaveToken is ERC20(1), VersionedInitializable {
-
- /// @dev snapshot of a value on a specific block, used for balances
- struct Snapshot {
- uint128 blockNumber;
- uint128 value;
- }
-
- string internal constant NAME = "Aave Token";
- string internal constant SYMBOL = "AAVE";
- uint8 internal constant DECIMALS = 18;
-
- /// @dev the amount being distributed for the LEND -> AAVE migration
- uint256 internal constant MIGRATION_AMOUNT = 13000000 ether;
-
- /// @dev the amount being distributed for the PSI and PEI
- uint256 internal constant DISTRIBUTION_AMOUNT = 3000000 ether;
-
- uint256 public constant REVISION = 1;
-
- /// @dev owner => next valid nonce to submit with permit()
- mapping (address => uint256) public _nonces;
-
- mapping (address => mapping (uint256 => Snapshot)) public _snapshots;
-
- mapping (address => uint256) public _countsSnapshots;
-
- /// @dev reference to the Aave governance contract to call (if initialized) on _beforeTokenTransfer
- /// !!! IMPORTANT The Aave governance is considered a trustable contract, being its responsibility
- /// to control all potential reentrancies by calling back the AaveToken
- ITransferHook public _aaveGovernance;
-
- bytes32 public DOMAIN_SEPARATOR;
- bytes public constant EIP712_REVISION = bytes("1");
- bytes32 internal constant EIP712_DOMAIN = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");
- bytes32 public constant PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
-
- event SnapshotDone(address owner, uint128 oldValue, uint128 newValue);
-
- constructor() ERC20(NAME, SYMBOL) public {}
-
- /**
- * @dev initializes the contract upon assignment to the InitializableAdminUpgradeabilityProxy
- * @param migrator the address of the LEND -> AAVE migration contract
- * @param distributor the address of the AAVE distribution contract
- */
- function initialize(
- address migrator,
- address distributor,
- ITransferHook aaveGovernance
- ) external initializer {
-
- uint256 chainId;
-
- //solium-disable-next-line
- assembly {
- chainId := chainid()
- }
-
- DOMAIN_SEPARATOR = keccak256(abi.encode(
- EIP712_DOMAIN,
- keccak256(bytes(NAME)),
- keccak256(EIP712_REVISION),
- chainId,
- address(this)
- ));
- _name = NAME;
- _symbol = SYMBOL;
- _setupDecimals(DECIMALS);
- _aaveGovernance = aaveGovernance;
- _mint(migrator, MIGRATION_AMOUNT);
- _mint(distributor, DISTRIBUTION_AMOUNT);
- }
-
- /**
- * @dev implements the permit function as for https://github.com/ethereum/EIPs/blob/8a34d644aacf0f9f8f00815307fd7dd5da07655f/EIPS/eip-2612.md
- * @param owner the owner of the funds
- * @param spender the spender
- * @param value the amount
- * @param deadline the deadline timestamp, type(uint256).max for no deadline
- * @param v signature param
- * @param s signature param
- * @param r signature param
- */
-
- function permit(
- address owner,
- address spender,
- uint256 value,
- uint256 deadline,
- uint8 v,
- bytes32 r,
- bytes32 s
- ) external {
- require(owner != address(0), "INVALID_OWNER");
- //solium-disable-next-line
- require(block.timestamp <= deadline, "INVALID_EXPIRATION");
- uint256 currentValidNonce = _nonces[owner];
- bytes32 digest = keccak256(
- abi.encodePacked(
- "\x19\x01",
- DOMAIN_SEPARATOR,
- keccak256(
- abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
- )
- );
-
- require(owner == ecrecover(digest, v, r, s), "INVALID_SIGNATURE");
- _nonces[owner] = currentValidNonce.add(1);
- _approve(owner, spender, value);
- }
-
- /**
- * @dev returns the revision of the implementation contract
- */
- function getRevision() internal pure override returns (uint256) {
- return REVISION;
- }
-
- /**
- * @dev Writes a snapshot for an owner of tokens
- * @param owner The owner of the tokens
- * @param oldValue The value before the operation that is gonna be executed after the snapshot
- * @param newValue The value after the operation
- */
- function _writeSnapshot(address owner, uint128 oldValue, uint128 newValue) internal {
- uint128 currentBlock = uint128(block.number);
-
- uint256 ownerCountOfSnapshots = _countsSnapshots[owner];
- mapping (uint256 => Snapshot) storage snapshotsOwner = _snapshots[owner];
-
- // Doing multiple operations in the same block
- if (ownerCountOfSnapshots != 0 && snapshotsOwner[ownerCountOfSnapshots.sub(1)].blockNumber == currentBlock) {
- snapshotsOwner[ownerCountOfSnapshots.sub(1)].value = newValue;
- } else {
- snapshotsOwner[ownerCountOfSnapshots] = Snapshot(currentBlock, newValue);
- _countsSnapshots[owner] = ownerCountOfSnapshots.add(1);
- }
-
- emit SnapshotDone(owner, oldValue, newValue);
- }
-
- /**
- * @dev Writes a snapshot before any operation involving transfer of value: _transfer, _mint and _burn
- * - On _transfer, it writes snapshots for both "from" and "to"
- * - On _mint, only for _to
- * - On _burn, only for _from
- * @param from the from address
- * @param to the to address
- * @param amount the amount to transfer
- */
- function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
- if (from == to) {
- return;
- }
-
- if (from != address(0)) {
- uint256 fromBalance = balanceOf(from);
- _writeSnapshot(from, uint128(fromBalance), uint128(fromBalance.sub(amount)));
- }
- if (to != address(0)) {
- uint256 toBalance = balanceOf(to);
- _writeSnapshot(to, uint128(toBalance), uint128(toBalance.add(amount)));
- }
-
- // caching the aave governance address to avoid multiple state loads
- ITransferHook aaveGovernance = _aaveGovernance;
- if (aaveGovernance != ITransferHook(0)) {
- aaveGovernance.onTransfer(from, to, amount);
- }
- }
-}
diff --git a/example/Aave/open-zeppelin/ERC20.sol b/example/Aave/open-zeppelin/ERC20.sol
deleted file mode 100644
index 7c53c69..0000000
--- a/example/Aave/open-zeppelin/ERC20.sol
+++ /dev/null
@@ -1,365 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC20.sol";
-import "./extensions/IERC20Metadata.sol";
-import "../../utils/Context.sol";
-
-/**
- * @dev Implementation of the {IERC20} interface.
- *
- * This implementation is agnostic to the way tokens are created. This means
- * that a supply mechanism has to be added in a derived contract using {_mint}.
- * For a generic mechanism see {ERC20PresetMinterPauser}.
- *
- * TIP: For a detailed writeup see our guide
- * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
- * to implement supply mechanisms].
- *
- * The default value of {decimals} is 18. To change this, you should override
- * this function so it returns a different value.
- *
- * We have followed general OpenZeppelin Contracts guidelines: functions revert
- * instead returning `false` on failure. This behavior is nonetheless
- * conventional and does not conflict with the expectations of ERC20
- * applications.
- *
- * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
- * This allows applications to reconstruct the allowance for all accounts just
- * by listening to said events. Other implementations of the EIP may not emit
- * these events, as it isn't required by the specification.
- *
- * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
- * functions have been added to mitigate the well-known issues around setting
- * allowances. See {IERC20-approve}.
- */
-contract ERC20 is Context, IERC20, IERC20Metadata {
- mapping(address => uint256) private _balances;
-
- mapping(address => mapping(address => uint256)) private _allowances;
-
- uint256 private _totalSupply;
-
- string private _name;
- string private _symbol;
-
- /**
- * @dev Sets the values for {name} and {symbol}.
- *
- * All two of these values are immutable: they can only be set once during
- * construction.
- */
- constructor(string memory name_, string memory symbol_) {
- _name = name_;
- _symbol = symbol_;
- }
-
- /**
- * @dev Returns the name of the token.
- */
- function name() public view virtual override returns (string memory) {
- return _name;
- }
-
- /**
- * @dev Returns the symbol of the token, usually a shorter version of the
- * name.
- */
- function symbol() public view virtual override returns (string memory) {
- return _symbol;
- }
-
- /**
- * @dev Returns the number of decimals used to get its user representation.
- * For example, if `decimals` equals `2`, a balance of `505` tokens should
- * be displayed to a user as `5.05` (`505 / 10 ** 2`).
- *
- * Tokens usually opt for a value of 18, imitating the relationship between
- * Ether and Wei. This is the default value returned by this function, unless
- * it's overridden.
- *
- * NOTE: This information is only used for _display_ purposes: it in
- * no way affects any of the arithmetic of the contract, including
- * {IERC20-balanceOf} and {IERC20-transfer}.
- */
- function decimals() public view virtual override returns (uint8) {
- return 18;
- }
-
- /**
- * @dev See {IERC20-totalSupply}.
- */
- function totalSupply() public view virtual override returns (uint256) {
- return _totalSupply;
- }
-
- /**
- * @dev See {IERC20-balanceOf}.
- */
- function balanceOf(address account) public view virtual override returns (uint256) {
- return _balances[account];
- }
-
- /**
- * @dev See {IERC20-transfer}.
- *
- * Requirements:
- *
- * - `to` cannot be the zero address.
- * - the caller must have a balance of at least `amount`.
- */
- function transfer(address to, uint256 amount) public virtual override returns (bool) {
- address owner = _msgSender();
- _transfer(owner, to, amount);
- return true;
- }
-
- /**
- * @dev See {IERC20-allowance}.
- */
- function allowance(address owner, address spender) public view virtual override returns (uint256) {
- return _allowances[owner][spender];
- }
-
- /**
- * @dev See {IERC20-approve}.
- *
- * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
- * `transferFrom`. This is semantically equivalent to an infinite approval.
- *
- * Requirements:
- *
- * - `spender` cannot be the zero address.
- */
- function approve(address spender, uint256 amount) public virtual override returns (bool) {
- address owner = _msgSender();
- _approve(owner, spender, amount);
- return true;
- }
-
- /**
- * @dev See {IERC20-transferFrom}.
- *
- * Emits an {Approval} event indicating the updated allowance. This is not
- * required by the EIP. See the note at the beginning of {ERC20}.
- *
- * NOTE: Does not update the allowance if the current allowance
- * is the maximum `uint256`.
- *
- * Requirements:
- *
- * - `from` and `to` cannot be the zero address.
- * - `from` must have a balance of at least `amount`.
- * - the caller must have allowance for ``from``'s tokens of at least
- * `amount`.
- */
- function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
- address spender = _msgSender();
- _spendAllowance(from, spender, amount);
- _transfer(from, to, amount);
- return true;
- }
-
- /**
- * @dev Atomically increases the allowance granted to `spender` by the caller.
- *
- * This is an alternative to {approve} that can be used as a mitigation for
- * problems described in {IERC20-approve}.
- *
- * Emits an {Approval} event indicating the updated allowance.
- *
- * Requirements:
- *
- * - `spender` cannot be the zero address.
- */
- function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
- address owner = _msgSender();
- _approve(owner, spender, allowance(owner, spender) + addedValue);
- return true;
- }
-
- /**
- * @dev Atomically decreases the allowance granted to `spender` by the caller.
- *
- * This is an alternative to {approve} that can be used as a mitigation for
- * problems described in {IERC20-approve}.
- *
- * Emits an {Approval} event indicating the updated allowance.
- *
- * Requirements:
- *
- * - `spender` cannot be the zero address.
- * - `spender` must have allowance for the caller of at least
- * `subtractedValue`.
- */
- function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
- address owner = _msgSender();
- uint256 currentAllowance = allowance(owner, spender);
- require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
- unchecked {
- _approve(owner, spender, currentAllowance - subtractedValue);
- }
-
- return true;
- }
-
- /**
- * @dev Moves `amount` of tokens from `from` to `to`.
- *
- * This internal function is equivalent to {transfer}, and can be used to
- * e.g. implement automatic token fees, slashing mechanisms, etc.
- *
- * Emits a {Transfer} event.
- *
- * Requirements:
- *
- * - `from` cannot be the zero address.
- * - `to` cannot be the zero address.
- * - `from` must have a balance of at least `amount`.
- */
- function _transfer(address from, address to, uint256 amount) internal virtual {
- require(from != address(0), "ERC20: transfer from the zero address");
- require(to != address(0), "ERC20: transfer to the zero address");
-
- _beforeTokenTransfer(from, to, amount);
-
- uint256 fromBalance = _balances[from];
- require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
- unchecked {
- _balances[from] = fromBalance - amount;
- // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
- // decrementing then incrementing.
- _balances[to] += amount;
- }
-
- emit Transfer(from, to, amount);
-
- _afterTokenTransfer(from, to, amount);
- }
-
- /** @dev Creates `amount` tokens and assigns them to `account`, increasing
- * the total supply.
- *
- * Emits a {Transfer} event with `from` set to the zero address.
- *
- * Requirements:
- *
- * - `account` cannot be the zero address.
- */
- function _mint(address account, uint256 amount) internal virtual {
- require(account != address(0), "ERC20: mint to the zero address");
-
- _beforeTokenTransfer(address(0), account, amount);
-
- _totalSupply += amount;
- unchecked {
- // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
- _balances[account] += amount;
- }
- emit Transfer(address(0), account, amount);
-
- _afterTokenTransfer(address(0), account, amount);
- }
-
- /**
- * @dev Destroys `amount` tokens from `account`, reducing the
- * total supply.
- *
- * Emits a {Transfer} event with `to` set to the zero address.
- *
- * Requirements:
- *
- * - `account` cannot be the zero address.
- * - `account` must have at least `amount` tokens.
- */
- function _burn(address account, uint256 amount) internal virtual {
- require(account != address(0), "ERC20: burn from the zero address");
-
- _beforeTokenTransfer(account, address(0), amount);
-
- uint256 accountBalance = _balances[account];
- require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
- unchecked {
- _balances[account] = accountBalance - amount;
- // Overflow not possible: amount <= accountBalance <= totalSupply.
- _totalSupply -= amount;
- }
-
- emit Transfer(account, address(0), amount);
-
- _afterTokenTransfer(account, address(0), amount);
- }
-
- /**
- * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
- *
- * This internal function is equivalent to `approve`, and can be used to
- * e.g. set automatic allowances for certain subsystems, etc.
- *
- * Emits an {Approval} event.
- *
- * Requirements:
- *
- * - `owner` cannot be the zero address.
- * - `spender` cannot be the zero address.
- */
- function _approve(address owner, address spender, uint256 amount) internal virtual {
- require(owner != address(0), "ERC20: approve from the zero address");
- require(spender != address(0), "ERC20: approve to the zero address");
-
- _allowances[owner][spender] = amount;
- emit Approval(owner, spender, amount);
- }
-
- /**
- * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
- *
- * Does not update the allowance amount in case of infinite allowance.
- * Revert if not enough allowance is available.
- *
- * Might emit an {Approval} event.
- */
- function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
- uint256 currentAllowance = allowance(owner, spender);
- if (currentAllowance != type(uint256).max) {
- require(currentAllowance >= amount, "ERC20: insufficient allowance");
- unchecked {
- _approve(owner, spender, currentAllowance - amount);
- }
- }
- }
-
- /**
- * @dev Hook that is called before any transfer of tokens. This includes
- * minting and burning.
- *
- * Calling conditions:
- *
- * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
- * will be transferred to `to`.
- * - when `from` is zero, `amount` tokens will be minted for `to`.
- * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
- * - `from` and `to` are never both zero.
- *
- * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
- */
- function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
-
- /**
- * @dev Hook that is called after any transfer of tokens. This includes
- * minting and burning.
- *
- * Calling conditions:
- *
- * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
- * has been transferred to `to`.
- * - when `from` is zero, `amount` tokens have been minted for `to`.
- * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
- * - `from` and `to` are never both zero.
- *
- * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
- */
- function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
-}
diff --git a/example/Aave/utils/VersionedInitializable.sol b/example/Aave/utils/VersionedInitializable.sol
deleted file mode 100644
index f12f352..0000000
--- a/example/Aave/utils/VersionedInitializable.sol
+++ /dev/null
@@ -1,70 +0,0 @@
-pragma solidity >=0.4.24 <0.6.0;
-
-/**
- * @title VersionedInitializable
- *
- * @dev Helper contract to support initializer functions. To use it, replace
- * the constructor with a function that has the `initializer` modifier.
- * WARNING: Unlike constructors, initializer functions must be manually
- * invoked. This applies both to deploying an Initializable contract, as well
- * as extending an Initializable contract via inheritance.
- * WARNING: When used with inheritance, manual care must be taken to not invoke
- * a parent initializer twice, or ensure that all initializers are idempotent,
- * because this is not dealt with automatically as with constructors.
- *
- * @author Aave, inspired by the OpenZeppelin Initializable contract
- */
-contract VersionedInitializable {
- /**
- * @dev Indicates that the contract has been initialized.
- */
- uint256 private lastInitializedRevision = 0;
-
- /**
- * @dev Indicates that the contract is in the process of being initialized.
- */
- bool private initializing;
-
- /**
- * @dev Modifier to use in the initializer function of a contract.
- */
- modifier initializer() {
- uint256 revision = getRevision();
- require(initializing || isConstructor() || revision > lastInitializedRevision, "Contract instance has already been initialized");
-
- bool isTopLevelCall = !initializing;
- if (isTopLevelCall) {
- initializing = true;
- lastInitializedRevision = revision;
- }
-
- _;
-
- if (isTopLevelCall) {
- initializing = false;
- }
- }
-
- /// @dev returns the revision number of the contract.
- /// Needs to be defined in the inherited class as a constant.
- function getRevision() internal pure returns(uint256);
-
-
- /// @dev Returns true if and only if the function is running in the constructor
- function isConstructor() private view returns (bool) {
- // extcodesize checks the size of the code stored in an address, and
- // address returns the current address. Since the code is still not
- // deployed when running a constructor, any checks on its code size will
- // yield zero, making it an effective way to detect if a contract is
- // under construction or not.
- uint256 cs;
- //solium-disable-next-line
- assembly {
-// cs := extcodesize(address)
- }
- return cs == 0;
- }
-
- // Reserved storage space to allow for layout changes in the future.
- uint256[50] private ______gap;
-}
diff --git a/example/ByteInst.sol b/example/ByteInst.sol
deleted file mode 100644
index 5872d83..0000000
--- a/example/ByteInst.sol
+++ /dev/null
@@ -1,11 +0,0 @@
-
-pragma solidity ^0.5.0;
-
-contract CloneFactory {
- function createClone()
- {
- x = byte(1);
-
- }
-
-}
\ No newline at end of file
diff --git a/example/Conduit.sol b/example/Conduit.sol
deleted file mode 100644
index 15f433e..0000000
--- a/example/Conduit.sol
+++ /dev/null
@@ -1,250 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.7;
-
-import { ConduitInterface } from "../interfaces/ConduitInterface.sol";
-
-import { ConduitItemType } from "./lib/ConduitEnums.sol";
-
-import { TokenTransferrer } from "../lib/TokenTransferrer.sol";
-
-import {
- ConduitTransfer,
- ConduitBatch1155Transfer
-} from "./lib/ConduitStructs.sol";
-
-import "./lib/ConduitConstants.sol";
-
-/**
- * @title Conduit
- * @author 0age
- * @notice This contract serves as an originator for "proxied" transfers. Each
- * conduit is deployed and controlled by a "conduit controller" that can
- * add and remove "channels" or contracts that can instruct the conduit
- * to transfer approved ERC20/721/1155 tokens. *IMPORTANT NOTE: each
- * conduit has an owner that can arbitrarily add or remove channels, and
- * a malicious or negligent owner can add a channel that allows for any
- * approved ERC20/721/1155 tokens to be taken immediately — be extremely
- * cautious with what conduits you give token approvals to!*
- */
-contract Conduit is ConduitInterface, TokenTransferrer {
- // Set deployer as an immutable controller that can update channel statuses.
- address private immutable _controller;
-
- // Track the status of each channel.
- mapping(address => bool) private _channels;
-
- /**
- * @notice Ensure that the caller is currently registered as an open channel
- * on the conduit.
- */
- modifier onlyOpenChannel() {
- // Utilize assembly to access channel storage mapping directly.
- assembly {
- // Write the caller to scratch space.
- mstore(ChannelKey_channel_ptr, caller())
-
- // Write the storage slot for _channels to scratch space.
- mstore(ChannelKey_slot_ptr, _channels.slot)
-
- // Derive the position in storage of _channels[msg.sender]
- // and check if the stored value is zero.
- if iszero(
- sload(keccak256(ChannelKey_channel_ptr, ChannelKey_length))
- ) {
- // The caller is not an open channel; revert with
- // ChannelClosed(caller). First, set error signature in memory.
- mstore(ChannelClosed_error_ptr, ChannelClosed_error_signature)
-
- // Next, set the caller as the argument.
- mstore(ChannelClosed_channel_ptr, caller())
-
- // Finally, revert, returning full custom error with argument.
- revert(ChannelClosed_error_ptr, ChannelClosed_error_length)
- }
- }
-
- // Continue with function execution.
- _;
- }
-
- /**
- * @notice In the constructor, set the deployer as the controller.
- */
- constructor() {
- // Set the deployer as the controller.
- _controller = msg.sender;
- }
-
- /**
- * @notice Execute a sequence of ERC20/721/1155 transfers. Only a caller
- * with an open channel can call this function. Note that channels
- * are expected to implement reentrancy protection if desired, and
- * that cross-channel reentrancy may be possible if the conduit has
- * multiple open channels at once. Also note that channels are
- * expected to implement checks against transferring any zero-amount
- * items if that constraint is desired.
- *
- * @param transfers The ERC20/721/1155 transfers to perform.
- *
- * @return magicValue A magic value indicating that the transfers were
- * performed successfully.
- */
- function execute(ConduitTransfer[] calldata transfers)
- external
- override
- onlyOpenChannel
- returns (bytes4 magicValue)
- {
- // Retrieve the total number of transfers and place on the stack.
- uint256 totalStandardTransfers = transfers.length;
-
- // Iterate over each transfer.
- for (uint256 i = 0; i < totalStandardTransfers; ) {
- // Retrieve the transfer in question and perform the transfer.
- _transfer(transfers[i]);
-
- // Skip overflow check as for loop is indexed starting at zero.
- unchecked {
- ++i;
- }
- }
-
- // Return a magic value indicating that the transfers were performed.
- magicValue = this.execute.selector;
- }
-
- /**
- * @notice Execute a sequence of batch 1155 item transfers. Only a caller
- * with an open channel can call this function. Note that channels
- * are expected to implement reentrancy protection if desired, and
- * that cross-channel reentrancy may be possible if the conduit has
- * multiple open channels at once. Also note that channels are
- * expected to implement checks against transferring any zero-amount
- * items if that constraint is desired.
- *
- * @param batchTransfers The 1155 batch item transfers to perform.
- *
- * @return magicValue A magic value indicating that the item transfers were
- * performed successfully.
- */
- function executeBatch1155(
- ConduitBatch1155Transfer[] calldata batchTransfers
- ) external override onlyOpenChannel returns (bytes4 magicValue) {
- // Perform 1155 batch transfers. Note that memory should be considered
- // entirely corrupted from this point forward.
- _performERC1155BatchTransfers(batchTransfers);
-
- // Return a magic value indicating that the transfers were performed.
- magicValue = this.executeBatch1155.selector;
- }
-
- /**
- * @notice Execute a sequence of transfers, both single ERC20/721/1155 item
- * transfers as well as batch 1155 item transfers. Only a caller
- * with an open channel can call this function. Note that channels
- * are expected to implement reentrancy protection if desired, and
- * that cross-channel reentrancy may be possible if the conduit has
- * multiple open channels at once. Also note that channels are
- * expected to implement checks against transferring any zero-amount
- * items if that constraint is desired.
- *
- * @param standardTransfers The ERC20/721/1155 item transfers to perform.
- * @param batchTransfers The 1155 batch item transfers to perform.
- *
- * @return magicValue A magic value indicating that the item transfers were
- * performed successfully.
- */
- function executeWithBatch1155(
- ConduitTransfer[] calldata standardTransfers,
- ConduitBatch1155Transfer[] calldata batchTransfers
- ) external override onlyOpenChannel returns (bytes4 magicValue) {
- // Retrieve the total number of transfers and place on the stack.
- uint256 totalStandardTransfers = standardTransfers.length;
-
- // Iterate over each standard transfer.
- for (uint256 i = 0; i < totalStandardTransfers; ) {
- // Retrieve the transfer in question and perform the transfer.
- _transfer(standardTransfers[i]);
-
- // Skip overflow check as for loop is indexed starting at zero.
- unchecked {
- ++i;
- }
- }
-
- // Perform 1155 batch transfers. Note that memory should be considered
- // entirely corrupted from this point forward aside from the free memory
- // pointer having the default value.
- _performERC1155BatchTransfers(batchTransfers);
-
- // Return a magic value indicating that the transfers were performed.
- magicValue = this.executeWithBatch1155.selector;
- }
-
- /**
- * @notice Open or close a given channel. Only callable by the controller.
- *
- * @param channel The channel to open or close.
- * @param isOpen The status of the channel (either open or closed).
- */
- function updateChannel(address channel, bool isOpen) external override {
- // Ensure that the caller is the controller of this contract.
- if (msg.sender != _controller) {
- revert InvalidController();
- }
-
- // Ensure that the channel does not already have the indicated status.
- if (_channels[channel] == isOpen) {
- revert ChannelStatusAlreadySet(channel, isOpen);
- }
-
- // Update the status of the channel.
- _channels[channel] = isOpen;
-
- // Emit a corresponding event.
- emit ChannelUpdated(channel, isOpen);
- }
-
- /**
- * @dev Internal function to transfer a given ERC20/721/1155 item. Note that
- * channels are expected to implement checks against transferring any
- * zero-amount items if that constraint is desired.
- *
- * @param item The ERC20/721/1155 item to transfer.
- */
- function _transfer(ConduitTransfer calldata item) internal {
- // Determine the transfer method based on the respective item type.
- if (item.itemType == ConduitItemType.ERC20) {
- // Transfer ERC20 token. Note that item.identifier is ignored and
- // therefore ERC20 transfer items are potentially malleable — this
- // check should be performed by the calling channel if a constraint
- // on item malleability is desired.
- _performERC20Transfer(item.token, item.from, item.to, item.amount);
- } else if (item.itemType == ConduitItemType.ERC721) {
- // Ensure that exactly one 721 item is being transferred.
- if (item.amount != 1) {
- revert InvalidERC721TransferAmount();
- }
-
- // Transfer ERC721 token.
- _performERC721Transfer(
- item.token,
- item.from,
- item.to,
- item.identifier
- );
- } else if (item.itemType == ConduitItemType.ERC1155) {
- // Transfer ERC1155 token.
- _performERC1155Transfer(
- item.token,
- item.from,
- item.to,
- item.identifier,
- item.amount
- );
- } else {
- // Throw with an error.
- revert InvalidItemType();
- }
- }
-}
diff --git a/example/FunctionsTest.sol b/example/FunctionsTest.sol
deleted file mode 100644
index 5dfd529..0000000
--- a/example/FunctionsTest.sol
+++ /dev/null
@@ -1,12 +0,0 @@
-pragma solidity 0.7.5;
-
-contract CloneFactory {
- function createClone(address target, bytes32 salt)
- internal
- returns (address payable result)
- {
- bytes20 targetBytes = bytes20(target);
-
- }
-
-}
\ No newline at end of file
diff --git a/example/ModifierVirtual.sol b/example/ModifierVirtual.sol
deleted file mode 100644
index a51c63a..0000000
--- a/example/ModifierVirtual.sol
+++ /dev/null
@@ -1,7 +0,0 @@
-pragma solidity 0.8.4;
-
-contract Owned {
- modifier onlyOwner() virtual {
-
- }
-}
\ No newline at end of file
diff --git a/example/SeaportInterface.sol b/example/SeaportInterface.sol
deleted file mode 100644
index fa30df8..0000000
--- a/example/SeaportInterface.sol
+++ /dev/null
@@ -1,439 +0,0 @@
-// SPDX-License-Identifier: MIT
-pragma solidity ^0.8.7;
-
-import {
- BasicOrderParameters,
- OrderComponents,
- Fulfillment,
- FulfillmentComponent,
- Execution,
- Order,
- AdvancedOrder,
- OrderStatus,
- CriteriaResolver
-} from "../lib/ConsiderationStructs.sol";
-
-/**
- * @title SeaportInterface
- * @author 0age
- * @custom:version 1.1
- * @notice Seaport is a generalized ETH/ERC20/ERC721/ERC1155 marketplace. It
- * minimizes external calls to the greatest extent possible and provides
- * lightweight methods for common routes as well as more flexible
- * methods for composing advanced orders.
- *
- * @dev SeaportInterface contains all external function interfaces for Seaport.
- */
-interface SeaportInterface {
- /**
- * @notice Fulfill an order offering an ERC721 token by supplying Ether (or
- * the native token for the given chain) as consideration for the
- * order. An arbitrary number of "additional recipients" may also be
- * supplied which will each receive native tokens from the fulfiller
- * as consideration.
- *
- * @param parameters Additional information on the fulfilled order. Note
- * that the offerer must first approve this contract (or
- * their preferred conduit if indicated by the order) for
- * their offered ERC721 token to be transferred.
- *
- * @return fulfilled A boolean indicating whether the order has been
- * successfully fulfilled.
- */
- function fulfillBasicOrder(BasicOrderParameters calldata parameters)
- external
- payable
- returns (bool fulfilled);
-
- /**
- * @notice Fulfill an order with an arbitrary number of items for offer and
- * consideration. Note that this function does not support
- * criteria-based orders or partial filling of orders (though
- * filling the remainder of a partially-filled order is supported).
- *
- * @param order The order to fulfill. Note that both the
- * offerer and the fulfiller must first approve
- * this contract (or the corresponding conduit if
- * indicated) to transfer any relevant tokens on
- * their behalf and that contracts must implement
- * `onERC1155Received` to receive ERC1155 tokens
- * as consideration.
- * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
- * any, to source the fulfiller's token approvals
- * from. The zero hash signifies that no conduit
- * should be used, with direct approvals set on
- * Seaport.
- *
- * @return fulfilled A boolean indicating whether the order has been
- * successfully fulfilled.
- */
- function fulfillOrder(Order calldata order, bytes32 fulfillerConduitKey)
- external
- payable
- returns (bool fulfilled);
-
- /**
- * @notice Fill an order, fully or partially, with an arbitrary number of
- * items for offer and consideration alongside criteria resolvers
- * containing specific token identifiers and associated proofs.
- *
- * @param advancedOrder The order to fulfill along with the fraction
- * of the order to attempt to fill. Note that
- * both the offerer and the fulfiller must first
- * approve this contract (or their preferred
- * conduit if indicated by the order) to transfer
- * any relevant tokens on their behalf and that
- * contracts must implement `onERC1155Received`
- * to receive ERC1155 tokens as consideration.
- * Also note that all offer and consideration
- * components must have no remainder after
- * multiplication of the respective amount with
- * the supplied fraction for the partial fill to
- * be considered valid.
- * @param criteriaResolvers An array where each element contains a
- * reference to a specific offer or
- * consideration, a token identifier, and a proof
- * that the supplied token identifier is
- * contained in the merkle root held by the item
- * in question's criteria element. Note that an
- * empty criteria indicates that any
- * (transferable) token identifier on the token
- * in question is valid and that no associated
- * proof needs to be supplied.
- * @param fulfillerConduitKey A bytes32 value indicating what conduit, if
- * any, to source the fulfiller's token approvals
- * from. The zero hash signifies that no conduit
- * should be used, with direct approvals set on
- * Seaport.
- * @param recipient The intended recipient for all received items,
- * with `address(0)` indicating that the caller
- * should receive the items.
- *
- * @return fulfilled A boolean indicating whether the order has been
- * successfully fulfilled.
- */
- function fulfillAdvancedOrder(
- AdvancedOrder calldata advancedOrder,
- CriteriaResolver[] calldata criteriaResolvers,
- bytes32 fulfillerConduitKey,
- address recipient
- ) external payable returns (bool fulfilled);
-
- /**
- * @notice Attempt to fill a group of orders, each with an arbitrary number
- * of items for offer and consideration. Any order that is not
- * currently active, has already been fully filled, or has been
- * cancelled will be omitted. Remaining offer and consideration
- * items will then be aggregated where possible as indicated by the
- * supplied offer and consideration component arrays and aggregated
- * items will be transferred to the fulfiller or to each intended
- * recipient, respectively. Note that a failing item transfer or an
- * issue with order formatting will cause the entire batch to fail.
- * Note that this function does not support criteria-based orders or
- * partial filling of orders (though filling the remainder of a
- * partially-filled order is supported).
- *
- * @param orders The orders to fulfill. Note that both
- * the offerer and the fulfiller must first
- * approve this contract (or the
- * corresponding conduit if indicated) to
- * transfer any relevant tokens on their
- * behalf and that contracts must implement
- * `onERC1155Received` to receive ERC1155
- * tokens as consideration.
- * @param offerFulfillments An array of FulfillmentComponent arrays
- * indicating which offer items to attempt
- * to aggregate when preparing executions.
- * @param considerationFulfillments An array of FulfillmentComponent arrays
- * indicating which consideration items to
- * attempt to aggregate when preparing
- * executions.
- * @param fulfillerConduitKey A bytes32 value indicating what conduit,
- * if any, to source the fulfiller's token
- * approvals from. The zero hash signifies
- * that no conduit should be used, with
- * direct approvals set on this contract.
- * @param maximumFulfilled The maximum number of orders to fulfill.
- *
- * @return availableOrders An array of booleans indicating if each order
- * with an index corresponding to the index of the
- * returned boolean was fulfillable or not.
- * @return executions An array of elements indicating the sequence of
- * transfers performed as part of matching the given
- * orders.
- */
- function fulfillAvailableOrders(
- Order[] calldata orders,
- FulfillmentComponent[][] calldata offerFulfillments,
- FulfillmentComponent[][] calldata considerationFulfillments,
- bytes32 fulfillerConduitKey,
- uint256 maximumFulfilled
- )
- external
- payable
- returns (bool[] memory availableOrders, Execution[] memory executions);
-
- /**
- * @notice Attempt to fill a group of orders, fully or partially, with an
- * arbitrary number of items for offer and consideration per order
- * alongside criteria resolvers containing specific token
- * identifiers and associated proofs. Any order that is not
- * currently active, has already been fully filled, or has been
- * cancelled will be omitted. Remaining offer and consideration
- * items will then be aggregated where possible as indicated by the
- * supplied offer and consideration component arrays and aggregated
- * items will be transferred to the fulfiller or to each intended
- * recipient, respectively. Note that a failing item transfer or an
- * issue with order formatting will cause the entire batch to fail.
- *
- * @param advancedOrders The orders to fulfill along with the
- * fraction of those orders to attempt to
- * fill. Note that both the offerer and the
- * fulfiller must first approve this
- * contract (or their preferred conduit if
- * indicated by the order) to transfer any
- * relevant tokens on their behalf and that
- * contracts must implement
- * `onERC1155Received` to enable receipt of
- * ERC1155 tokens as consideration. Also
- * note that all offer and consideration
- * components must have no remainder after
- * multiplication of the respective amount
- * with the supplied fraction for an
- * order's partial fill amount to be
- * considered valid.
- * @param criteriaResolvers An array where each element contains a
- * reference to a specific offer or
- * consideration, a token identifier, and a
- * proof that the supplied token identifier
- * is contained in the merkle root held by
- * the item in question's criteria element.
- * Note that an empty criteria indicates
- * that any (transferable) token
- * identifier on the token in question is
- * valid and that no associated proof needs
- * to be supplied.
- * @param offerFulfillments An array of FulfillmentComponent arrays
- * indicating which offer items to attempt
- * to aggregate when preparing executions.
- * @param considerationFulfillments An array of FulfillmentComponent arrays
- * indicating which consideration items to
- * attempt to aggregate when preparing
- * executions.
- * @param fulfillerConduitKey A bytes32 value indicating what conduit,
- * if any, to source the fulfiller's token
- * approvals from. The zero hash signifies
- * that no conduit should be used, with
- * direct approvals set on this contract.
- * @param recipient The intended recipient for all received
- * items, with `address(0)` indicating that
- * the caller should receive the items.
- * @param maximumFulfilled The maximum number of orders to fulfill.
- *
- * @return availableOrders An array of booleans indicating if each order
- * with an index corresponding to the index of the
- * returned boolean was fulfillable or not.
- * @return executions An array of elements indicating the sequence of
- * transfers performed as part of matching the given
- * orders.
- */
- function fulfillAvailableAdvancedOrders(
- AdvancedOrder[] calldata advancedOrders,
- CriteriaResolver[] calldata criteriaResolvers,
- FulfillmentComponent[][] calldata offerFulfillments,
- FulfillmentComponent[][] calldata considerationFulfillments,
- bytes32 fulfillerConduitKey,
- address recipient,
- uint256 maximumFulfilled
- )
- external
- payable
- returns (bool[] memory availableOrders, Execution[] memory executions);
-
- /**
- * @notice Match an arbitrary number of orders, each with an arbitrary
- * number of items for offer and consideration along with as set of
- * fulfillments allocating offer components to consideration
- * components. Note that this function does not support
- * criteria-based or partial filling of orders (though filling the
- * remainder of a partially-filled order is supported).
- *
- * @param orders The orders to match. Note that both the offerer and
- * fulfiller on each order must first approve this
- * contract (or their conduit if indicated by the order)
- * to transfer any relevant tokens on their behalf and
- * each consideration recipient must implement
- * `onERC1155Received` to enable ERC1155 token receipt.
- * @param fulfillments An array of elements allocating offer components to
- * consideration components. Note that each
- * consideration component must be fully met for the
- * match operation to be valid.
- *
- * @return executions An array of elements indicating the sequence of
- * transfers performed as part of matching the given
- * orders.
- */
- function matchOrders(
- Order[] calldata orders,
- Fulfillment[] calldata fulfillments
- ) external payable returns (Execution[] memory executions);
-
- /**
- * @notice Match an arbitrary number of full or partial orders, each with an
- * arbitrary number of items for offer and consideration, supplying
- * criteria resolvers containing specific token identifiers and
- * associated proofs as well as fulfillments allocating offer
- * components to consideration components.
- *
- * @param orders The advanced orders to match. Note that both the
- * offerer and fulfiller on each order must first
- * approve this contract (or a preferred conduit if
- * indicated by the order) to transfer any relevant
- * tokens on their behalf and each consideration
- * recipient must implement `onERC1155Received` in
- * order to receive ERC1155 tokens. Also note that
- * the offer and consideration components for each
- * order must have no remainder after multiplying
- * the respective amount with the supplied fraction
- * in order for the group of partial fills to be
- * considered valid.
- * @param criteriaResolvers An array where each element contains a reference
- * to a specific order as well as that order's
- * offer or consideration, a token identifier, and
- * a proof that the supplied token identifier is
- * contained in the order's merkle root. Note that
- * an empty root indicates that any (transferable)
- * token identifier is valid and that no associated
- * proof needs to be supplied.
- * @param fulfillments An array of elements allocating offer components
- * to consideration components. Note that each
- * consideration component must be fully met in
- * order for the match operation to be valid.
- *
- * @return executions An array of elements indicating the sequence of
- * transfers performed as part of matching the given
- * orders.
- */
- function matchAdvancedOrders(
- AdvancedOrder[] calldata orders,
- CriteriaResolver[] calldata criteriaResolvers,
- Fulfillment[] calldata fulfillments
- ) external payable returns (Execution[] memory executions);
-
- /**
- * @notice Cancel an arbitrary number of orders. Note that only the offerer
- * or the zone of a given order may cancel it. Callers should ensure
- * that the intended order was cancelled by calling `getOrderStatus`
- * and confirming that `isCancelled` returns `true`.
- *
- * @param orders The orders to cancel.
- *
- * @return cancelled A boolean indicating whether the supplied orders have
- * been successfully cancelled.
- */
- function cancel(OrderComponents[] calldata orders)
- external
- returns (bool cancelled);
-
- /**
- * @notice Validate an arbitrary number of orders, thereby registering their
- * signatures as valid and allowing the fulfiller to skip signature
- * verification on fulfillment. Note that validated orders may still
- * be unfulfillable due to invalid item amounts or other factors;
- * callers should determine whether validated orders are fulfillable
- * by simulating the fulfillment call prior to execution. Also note
- * that anyone can validate a signed order, but only the offerer can
- * validate an order without supplying a signature.
- *
- * @param orders The orders to validate.
- *
- * @return validated A boolean indicating whether the supplied orders have
- * been successfully validated.
- */
- function validate(Order[] calldata orders)
- external
- returns (bool validated);
-
- /**
- * @notice Cancel all orders from a given offerer with a given zone in bulk
- * by incrementing a counter. Note that only the offerer may
- * increment the counter.
- *
- * @return newCounter The new counter.
- */
- function incrementCounter() external returns (uint256 newCounter);
-
- /**
- * @notice Retrieve the order hash for a given order.
- *
- * @param order The components of the order.
- *
- * @return orderHash The order hash.
- */
- function getOrderHash(OrderComponents calldata order)
- external
- view
- returns (bytes32 orderHash);
-
- /**
- * @notice Retrieve the status of a given order by hash, including whether
- * the order has been cancelled or validated and the fraction of the
- * order that has been filled.
- *
- * @param orderHash The order hash in question.
- *
- * @return isValidated A boolean indicating whether the order in question
- * has been validated (i.e. previously approved or
- * partially filled).
- * @return isCancelled A boolean indicating whether the order in question
- * has been cancelled.
- * @return totalFilled The total portion of the order that has been filled
- * (i.e. the "numerator").
- * @return totalSize The total size of the order that is either filled or
- * unfilled (i.e. the "denominator").
- */
- function getOrderStatus(bytes32 orderHash)
- external
- view
- returns (
- bool isValidated,
- bool isCancelled,
- uint256 totalFilled,
- uint256 totalSize
- );
-
- /**
- * @notice Retrieve the current counter for a given offerer.
- *
- * @param offerer The offerer in question.
- *
- * @return counter The current counter.
- */
- function getCounter(address offerer)
- external
- view
- returns (uint256 counter);
-
- /**
- * @notice Retrieve configuration information for this contract.
- *
- * @return version The contract version.
- * @return domainSeparator The domain separator for this contract.
- * @return conduitController The conduit Controller set for this contract.
- */
- function information()
- external
- view
- returns (
- string memory version,
- bytes32 domainSeparator,
- address conduitController
- );
-
- /**
- * @notice Retrieve the name of this contract.
- *
- * @return contractName The name of this contract.
- */
- function name() external view returns (string memory contractName);
-}
diff --git a/example/TestInput.json b/example/TestInput.json
deleted file mode 100644
index 1af72c3..0000000
--- a/example/TestInput.json
+++ /dev/null
@@ -1,153 +0,0 @@
-{
- "language": "Solidity",
- "sources": {
- "contracts/amm/TempusAMM.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity 0.7.6;\npragma experimental ABIEncoderV2;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/helpers/InputHelpers.sol\";\n\nimport \"@balancer-labs/v2-pool-utils/contracts/BaseGeneralPool.sol\";\nimport \"@balancer-labs/v2-pool-utils/contracts/BaseMinimalSwapInfoPool.sol\";\n\nimport \"@balancer-labs/v2-pool-stable/contracts/StableMath.sol\";\n\nimport \"./interfaces/IRateProvider.sol\";\nimport \"./../ITempusPool.sol\";\nimport \"./../token/IPoolShare.sol\";\nimport \"./TempusAMMUserDataHelpers.sol\";\nimport \"./VecMath.sol\";\n\ncontract TempusAMM is BaseMinimalSwapInfoPool, StableMath, IRateProvider {\n using FixedPoint for uint256;\n using TempusAMMUserDataHelpers for bytes;\n using VecMath for uint256[];\n\n // This contract uses timestamps to slowly update its Amplification parameter over time. These changes must occur\n // over a minimum time period much larger than the blocktime, making timestamp manipulation a non-issue.\n // solhint-disable not-rely-on-time\n\n // Amplification factor changes must happen over a minimum period of one day, and can at most divide or multiple the\n // current value by 2 every day.\n // WARNING: this only limits *a single* amplification change to have a maximum rate of change of twice the original\n // value daily. It is possible to perform multiple amplification changes in sequence to increase this value more\n // rapidly: for example, by doubling the value every day it can increase by a factor of 8 over three days (2^3).\n uint256 private constant _MIN_UPDATE_TIME = 1 days;\n uint256 private constant _MAX_AMP_UPDATE_DAILY_RATE = 2;\n uint256 private immutable _TEMPUS_SHARE_PRECISION;\n uint256 private constant _TOTAL_TOKENS = 2;\n\n struct AmplificationData {\n uint64 startValue;\n uint64 endValue;\n uint64 startTime;\n uint64 endTime;\n }\n\n AmplificationData private _amplificationData;\n\n event AmpUpdateStarted(uint256 startValue, uint256 endValue, uint256 startTime, uint256 endTime);\n event AmpUpdateStopped(uint256 currentValue);\n\n IPoolShare internal immutable _token0;\n IPoolShare internal immutable _token1;\n\n // All token balances are normalized to behave as if the token had 18 decimals. We assume a token's decimals will\n // not change throughout its lifetime, and store the corresponding scaling factor for each at construction time.\n // These factors are always greater than or equal to one: tokens with more than 18 decimals are not supported.\n\n uint256 internal immutable _scalingFactor0;\n uint256 internal immutable _scalingFactor1;\n\n // To track how many tokens are owed to the Vault as protocol fees, we measure and store the value of the invariant\n // after every join and exit. All invariant growth that happens between join and exit events is due to swap fees.\n uint256 internal _lastInvariant;\n\n // Because the invariant depends on the amplification parameter, and this value may change over time, we should only\n // compare invariants that were computed using the same value. We therefore store it whenever we store\n // _lastInvariant.\n uint256 internal _lastInvariantAmp;\n\n ITempusPool public immutable tempusPool;\n\n enum JoinKind {\n INIT,\n EXACT_TOKENS_IN_FOR_BPT_OUT\n }\n enum ExitKind {\n EXACT_BPT_IN_FOR_TOKENS_OUT,\n BPT_IN_FOR_EXACT_TOKENS_OUT\n }\n\n constructor(\n IVault vault,\n string memory name,\n string memory symbol,\n ITempusPool pool,\n uint256 amplificationStart,\n uint256 amplificationEnd,\n uint256 swapFeePercentage,\n uint256 pauseWindowDuration,\n uint256 bufferPeriodDuration,\n address owner\n )\n BasePool(\n vault,\n // Because we're inheriting from both BaseGeneralPool and BaseMinimalSwapInfoPool we can choose any\n // specialization setting. Since this Pool never registers or deregisters any tokens after construction,\n // picking Two Token when the Pool only has two tokens is free gas savings.\n IVault.PoolSpecialization.TWO_TOKEN,\n name,\n symbol,\n _mapTempusSharesToIERC20(pool),\n new address[](2),\n swapFeePercentage,\n pauseWindowDuration,\n bufferPeriodDuration,\n owner\n )\n {\n _require(amplificationStart >= _MIN_AMP, Errors.MIN_AMP);\n _require(amplificationStart <= _MAX_AMP, Errors.MAX_AMP);\n\n IPoolShare yieldShare = pool.yieldShare();\n IPoolShare principalShare = pool.principalShare();\n\n require(\n ERC20(address(principalShare)).decimals() == ERC20(address(yieldShare)).decimals(),\n \"Principals and Yields need same precision.\"\n );\n _TEMPUS_SHARE_PRECISION = 10**ERC20(address(principalShare)).decimals();\n\n // Immutable variables cannot be initialized inside an if statement, so we must do conditional assignments\n (IPoolShare token0, IPoolShare token1) = yieldShare < principalShare\n ? (yieldShare, principalShare)\n : (principalShare, yieldShare);\n (_token0, _token1) = (token0, token1);\n\n tempusPool = pool;\n\n _scalingFactor0 = _computeScalingFactor(IERC20(address(token0)));\n _scalingFactor1 = _computeScalingFactor(IERC20(address(token1)));\n\n uint256 initialAmp = Math.mul(amplificationStart, _AMP_PRECISION);\n _setAmplificationData(initialAmp);\n\n if (amplificationStart != amplificationEnd) {\n _require(amplificationStart < amplificationEnd, Errors.MIN_AMP);\n _startAmplificationParameterUpdate(amplificationEnd, pool.maturityTime());\n }\n }\n\n function getLastInvariant() external view returns (uint256 lastInvariant, uint256 lastInvariantAmp) {\n lastInvariant = _lastInvariant;\n lastInvariantAmp = _lastInvariantAmp;\n }\n\n function getExpectedReturnGivenIn(uint256 amount, bool yieldShareIn) public view returns (uint256) {\n (, uint256[] memory balances, ) = getVault().getPoolTokens(getPoolId());\n (uint256 currentAmp, ) = _getAmplificationParameter();\n (IPoolShare tokenIn, IPoolShare tokenOut) = yieldShareIn\n ? (tempusPool.yieldShare(), tempusPool.principalShare())\n : (tempusPool.principalShare(), tempusPool.yieldShare());\n (uint256 indexIn, uint256 indexOut) = address(tokenIn) == address(_token0) ? (0, 1) : (1, 0);\n\n amount = _subtractSwapFeeAmount(amount);\n balances.mul(_getTokenRatesStored(), _TEMPUS_SHARE_PRECISION);\n uint256 rateAdjustedSwapAmount = (amount * tokenIn.getPricePerFullShareStored()) / _TEMPUS_SHARE_PRECISION;\n\n uint256 amountOut = StableMath._calcOutGivenIn(currentAmp, balances, indexIn, indexOut, rateAdjustedSwapAmount);\n amountOut = (amountOut * _TEMPUS_SHARE_PRECISION) / tokenOut.getPricePerFullShareStored();\n\n return amountOut;\n }\n\n function getSwapAmountToEndWithEqualShares(\n uint256 principals,\n uint256 yields,\n uint256 threshold\n ) external view returns (uint256 amountIn, bool yieldsIn) {\n uint256 difference;\n (difference, yieldsIn) = (principals > yields) ? (principals - yields, false) : (yields - principals, true);\n\n if (difference > threshold) {\n uint256 principalsRate = tempusPool.principalShare().getPricePerFullShareStored();\n uint256 yieldsRate = tempusPool.yieldShare().getPricePerFullShareStored();\n\n uint256 rate = yieldsIn\n ? (principalsRate * _TEMPUS_SHARE_PRECISION) / yieldsRate\n : (yieldsRate * _TEMPUS_SHARE_PRECISION) / principalsRate;\n for (uint256 i = 0; i < 32; i++) {\n // if we have accurate rate this should hold\n amountIn = (difference * _TEMPUS_SHARE_PRECISION) / (rate + _TEMPUS_SHARE_PRECISION);\n uint256 amountOut = getExpectedReturnGivenIn(amountIn, yieldsIn);\n uint256 newPrincipals = yieldsIn ? (principals + amountOut) : (principals - amountIn);\n uint256 newYields = yieldsIn ? (yields - amountIn) : (yields + amountOut);\n uint256 newDifference = (newPrincipals > newYields)\n ? (newPrincipals - newYields)\n : (newYields - newPrincipals);\n if (newDifference < threshold) {\n return (amountIn, yieldsIn);\n } else {\n rate = (amountOut * _TEMPUS_SHARE_PRECISION) / amountIn;\n }\n }\n revert(\"getSwapAmountToEndWithEqualShares did not converge.\");\n }\n }\n\n // NOTE: Return value in AMM decimals precision (1e18)\n function getExpectedBPTInGivenTokensOut(uint256 principalsStaked, uint256 yieldsStaked)\n external\n view\n returns (uint256 lpTokens)\n {\n (IERC20[] memory ammTokens, uint256[] memory balances, ) = getVault().getPoolTokens(getPoolId());\n uint256[] memory amountsOut = new uint256[](2);\n (amountsOut[0], amountsOut[1]) = (address(ammTokens[0]) == address(tempusPool.principalShare()))\n ? (principalsStaked, yieldsStaked)\n : (yieldsStaked, principalsStaked);\n\n uint256[] memory scalingFactors = _scalingFactors();\n _upscaleArray(amountsOut, scalingFactors);\n _upscaleArray(balances, scalingFactors);\n uint256[] memory tokenRates = _getTokenRatesStored();\n amountsOut.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n balances.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n uint256 protocolSwapFeePercentage = getSwapFeePercentage();\n if (_isNotPaused()) {\n // Update current balances by subtracting the protocol fee amounts\n balances.sub(_getDueProtocolFeeAmounts(balances, protocolSwapFeePercentage));\n }\n\n (uint256 currentAmp, ) = _getAmplificationParameter();\n lpTokens = StableMath._calcBptInGivenExactTokensOut(\n currentAmp,\n balances,\n amountsOut,\n totalSupply(),\n protocolSwapFeePercentage\n );\n }\n\n function getExpectedTokensOutGivenBPTIn(uint256 bptAmountIn)\n external\n view\n returns (uint256 principals, uint256 yields)\n {\n // We don't need to scale balances down here\n // as calculation for amounts out is based on btpAmountIn / totalSupply() ratio\n // Adjusting balances with rate, and then undoing it would just cause additional calculations\n (, uint256[] memory balances, ) = getVault().getPoolTokens(getPoolId());\n uint256[] memory amountsOut = StableMath._calcTokensOutGivenExactBptIn(balances, bptAmountIn, totalSupply());\n (principals, yields) = (address(_token0) == address(tempusPool.principalShare()))\n ? (amountsOut[0], amountsOut[1])\n : (amountsOut[1], amountsOut[0]);\n }\n\n function getExpectedLPTokensForTokensIn(uint256[] memory amountsIn) external view returns (uint256) {\n (, uint256[] memory balances, ) = getVault().getPoolTokens(getPoolId());\n\n uint256[] memory tokenRates = _getTokenRatesStored();\n balances.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n amountsIn.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n (uint256 currentAmp, ) = _getAmplificationParameter();\n\n return\n (balances[0] == 0)\n ? StableMath._calculateInvariant(currentAmp, amountsIn, true)\n : StableMath._calcBptOutGivenExactTokensIn(\n currentAmp,\n balances,\n amountsIn,\n totalSupply(),\n getSwapFeePercentage()\n );\n }\n\n // Base Pool handlers\n\n // Swap - Two Token Pool specialization (from BaseMinimalSwapInfoPool)\n\n function _onSwapGivenIn(\n SwapRequest memory swapRequest,\n uint256 balanceTokenIn,\n uint256 balanceTokenOut\n ) internal virtual override returns (uint256) {\n (uint256[] memory balances, uint256 indexIn, uint256 indexOut) = _getSwapBalanceArrays(\n swapRequest,\n balanceTokenIn,\n balanceTokenOut\n );\n\n (uint256 currentAmp, ) = _getAmplificationParameter();\n uint256[] memory rates = _getTokenRates();\n uint256 tokenInRate = rates[indexIn];\n uint256 tokenOutRate = rates[indexOut];\n\n balances.mul(rates, _TEMPUS_SHARE_PRECISION);\n uint256 rateAdjustedSwapAmount = (swapRequest.amount * tokenInRate) / _TEMPUS_SHARE_PRECISION;\n\n uint256 amountOut = StableMath._calcOutGivenIn(currentAmp, balances, indexIn, indexOut, rateAdjustedSwapAmount);\n return (amountOut * _TEMPUS_SHARE_PRECISION) / tokenOutRate;\n }\n\n function _onSwapGivenOut(\n SwapRequest memory,\n uint256,\n uint256\n ) internal virtual override returns (uint256) {\n revert(\"Unsupported swap type\");\n }\n\n function _getSwapBalanceArrays(\n SwapRequest memory swapRequest,\n uint256 balanceTokenIn,\n uint256 balanceTokenOut\n )\n private\n view\n returns (\n uint256[] memory balances,\n uint256 indexIn,\n uint256 indexOut\n )\n {\n balances = new uint256[](2);\n\n if (address(_token0) == address(swapRequest.tokenIn)) {\n indexIn = 0;\n indexOut = 1;\n\n balances[0] = balanceTokenIn;\n balances[1] = balanceTokenOut;\n } else {\n indexOut = 0;\n indexIn = 1;\n\n balances[0] = balanceTokenOut;\n balances[1] = balanceTokenIn;\n }\n }\n\n // Initialize\n\n function _onInitializePool(\n bytes32,\n address,\n address,\n uint256[] memory scalingFactors,\n bytes memory userData\n ) internal virtual override whenNotPaused returns (uint256, uint256[] memory) {\n // It would be strange for the Pool to be paused before it is initialized, but for consistency we prevent\n // initialization in this case.\n TempusAMM.JoinKind kind = userData.joinKind();\n _require(kind == TempusAMM.JoinKind.INIT, Errors.UNINITIALIZED);\n\n uint256[] memory amountsIn = userData.initialAmountsIn();\n InputHelpers.ensureInputLengthMatch(amountsIn.length, _TOTAL_TOKENS);\n _upscaleArray(amountsIn, scalingFactors);\n\n uint256[] memory tokenRates = _getTokenRates();\n amountsIn.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n (uint256 currentAmp, ) = _getAmplificationParameter();\n uint256 invariantAfterJoin = StableMath._calculateInvariant(currentAmp, amountsIn, true);\n\n // Set the initial BPT to the value of the invariant.\n uint256 bptAmountOut = invariantAfterJoin;\n\n _updateLastInvariant(invariantAfterJoin, currentAmp);\n\n amountsIn.div(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n return (bptAmountOut, amountsIn);\n }\n\n // Join\n\n function _onJoinPool(\n bytes32,\n address,\n address,\n uint256[] memory balances,\n uint256,\n uint256 protocolSwapFeePercentage,\n uint256[] memory scalingFactors,\n bytes memory userData\n )\n internal\n virtual\n override\n whenNotPaused\n returns (\n uint256,\n uint256[] memory,\n uint256[] memory\n )\n {\n uint256[] memory tokenRates = _getTokenRates();\n balances.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n // Due protocol swap fee amounts are computed by measuring the growth of the invariant between the previous join\n // or exit event and now - the invariant's growth is due exclusively to swap fees. This avoids spending gas to\n // calculate the fee amounts during each individual swap.\n uint256[] memory dueProtocolFeeAmounts = _getDueProtocolFeeAmounts(balances, protocolSwapFeePercentage);\n\n // Update current balances by subtracting the protocol fee amounts\n balances.sub(dueProtocolFeeAmounts);\n (uint256 bptAmountOut, uint256[] memory amountsIn) = _doJoin(balances, scalingFactors, tokenRates, userData);\n\n // Update the invariant with the balances the Pool will have after the join, in order to compute the\n // protocol swap fee amounts due in future joins and exits.\n _updateInvariantAfterJoin(balances, amountsIn);\n\n amountsIn.div(tokenRates, _TEMPUS_SHARE_PRECISION);\n dueProtocolFeeAmounts.div(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n return (bptAmountOut, amountsIn, dueProtocolFeeAmounts);\n }\n\n function _doJoin(\n uint256[] memory balances,\n uint256[] memory scalingFactors,\n uint256[] memory tokenRates,\n bytes memory userData\n ) private returns (uint256 bptAmountOut, uint256[] memory amountsIn) {\n JoinKind kind = userData.joinKind();\n\n if (kind == JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT) {\n return _joinExactTokensInForBPTOut(balances, scalingFactors, tokenRates, userData);\n } else {\n _revert(Errors.UNHANDLED_JOIN_KIND);\n }\n }\n\n function _joinExactTokensInForBPTOut(\n uint256[] memory balances,\n uint256[] memory scalingFactors,\n uint256[] memory tokenRates,\n bytes memory userData\n ) private view returns (uint256, uint256[] memory) {\n (uint256[] memory amountsIn, uint256 minBPTAmountOut) = userData.exactTokensInForBptOut();\n InputHelpers.ensureInputLengthMatch(_TOTAL_TOKENS, amountsIn.length);\n\n _upscaleArray(amountsIn, scalingFactors);\n amountsIn.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n (uint256 currentAmp, ) = _getAmplificationParameter();\n\n uint256 bptAmountOut = StableMath._calcBptOutGivenExactTokensIn(\n currentAmp,\n balances,\n amountsIn,\n totalSupply(),\n getSwapFeePercentage()\n );\n\n _require(bptAmountOut >= minBPTAmountOut, Errors.BPT_OUT_MIN_AMOUNT);\n\n return (bptAmountOut, amountsIn);\n }\n\n // Exit\n\n function _onExitPool(\n bytes32,\n address,\n address,\n uint256[] memory balances,\n uint256,\n uint256 protocolSwapFeePercentage,\n uint256[] memory scalingFactors,\n bytes memory userData\n )\n internal\n virtual\n override\n returns (\n uint256 bptAmountIn,\n uint256[] memory amountsOut,\n uint256[] memory dueProtocolFeeAmounts\n )\n {\n uint256[] memory tokenRates = _getTokenRates();\n balances.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n // Exits are not completely disabled while the contract is paused: proportional exits (exact BPT in for tokens\n // out) remain functional.\n\n if (_isNotPaused()) {\n // Due protocol swap fee amounts are computed by measuring the growth of the invariant between the previous\n // join or exit event and now - the invariant's growth is due exclusively to swap fees. This avoids\n // spending gas calculating fee amounts during each individual swap\n dueProtocolFeeAmounts = _getDueProtocolFeeAmounts(balances, protocolSwapFeePercentage);\n\n // Update current balances by subtracting the protocol fee amounts\n balances.sub(dueProtocolFeeAmounts);\n } else {\n // If the contract is paused, swap protocol fee amounts are not charged to avoid extra calculations and\n // reduce the potential for errors.\n dueProtocolFeeAmounts = new uint256[](_TOTAL_TOKENS);\n }\n\n (bptAmountIn, amountsOut) = _doExit(balances, scalingFactors, tokenRates, userData);\n\n // Update the invariant with the balances the Pool will have after the exit, in order to compute the\n // protocol swap fee amounts due in future joins and exits.\n _updateInvariantAfterExit(balances, amountsOut);\n\n amountsOut.div(tokenRates, _TEMPUS_SHARE_PRECISION);\n dueProtocolFeeAmounts.div(tokenRates, _TEMPUS_SHARE_PRECISION);\n }\n\n function _doExit(\n uint256[] memory balances,\n uint256[] memory scalingFactors,\n uint256[] memory tokenRates,\n bytes memory userData\n ) private returns (uint256, uint256[] memory) {\n ExitKind kind = userData.exitKind();\n\n if (kind == ExitKind.EXACT_BPT_IN_FOR_TOKENS_OUT) {\n return _exitExactBPTInForTokensOut(balances, userData);\n } else if (kind == ExitKind.BPT_IN_FOR_EXACT_TOKENS_OUT) {\n return _exitBPTInForExactTokensOut(balances, scalingFactors, tokenRates, userData);\n } else {\n revert(\"Unhandled exit kind.\");\n }\n }\n\n function _exitExactBPTInForTokensOut(uint256[] memory balances, bytes memory userData)\n private\n view\n returns (uint256, uint256[] memory)\n {\n // This exit function is the only one that is not disabled if the contract is paused: it remains unrestricted\n // in an attempt to provide users with a mechanism to retrieve their tokens in case of an emergency.\n // This particular exit function is the only one that remains available because it is the simplest one, and\n // therefore the one with the lowest likelihood of errors.\n\n uint256 bptAmountIn = userData.exactBptInForTokensOut();\n // Note that there is no minimum amountOut parameter: this is handled by `IVault.exitPool`.\n\n uint256[] memory amountsOut = StableMath._calcTokensOutGivenExactBptIn(balances, bptAmountIn, totalSupply());\n return (bptAmountIn, amountsOut);\n }\n\n function _exitBPTInForExactTokensOut(\n uint256[] memory balances,\n uint256[] memory scalingFactors,\n uint256[] memory tokenRates,\n bytes memory userData\n ) private view whenNotPaused returns (uint256, uint256[] memory) {\n // This exit function is disabled if the contract is paused.\n\n (uint256[] memory amountsOut, uint256 maxBPTAmountIn) = userData.bptInForExactTokensOut();\n InputHelpers.ensureInputLengthMatch(amountsOut.length, _TOTAL_TOKENS);\n _upscaleArray(amountsOut, scalingFactors);\n\n amountsOut.mul(tokenRates, _TEMPUS_SHARE_PRECISION);\n\n (uint256 currentAmp, ) = _getAmplificationParameter();\n uint256 bptAmountIn = StableMath._calcBptInGivenExactTokensOut(\n currentAmp,\n balances,\n amountsOut,\n totalSupply(),\n getSwapFeePercentage()\n );\n _require(bptAmountIn <= maxBPTAmountIn, Errors.BPT_IN_MAX_AMOUNT);\n\n return (bptAmountIn, amountsOut);\n }\n\n // Helpers\n\n /**\n * @dev Stores the last measured invariant, and the amplification parameter used to compute it.\n */\n function _updateLastInvariant(uint256 invariant, uint256 amplificationParameter) private {\n _lastInvariant = invariant;\n _lastInvariantAmp = amplificationParameter;\n }\n\n /**\n * @dev Returns the amount of protocol fees to pay, given the value of the last stored invariant and the current\n * balances.\n */\n function _getDueProtocolFeeAmounts(uint256[] memory balances, uint256 protocolSwapFeePercentage)\n private\n view\n returns (uint256[] memory)\n {\n // Initialize with zeros\n uint256[] memory dueProtocolFeeAmounts = new uint256[](_TOTAL_TOKENS);\n\n // Early return if the protocol swap fee percentage is zero, saving gas.\n if (protocolSwapFeePercentage == 0) {\n return dueProtocolFeeAmounts;\n }\n\n // Instead of paying the protocol swap fee in all tokens proportionally, we will pay it in a single one. This\n // will reduce gas costs for single asset joins and exits, as at most only two Pool balances will change (the\n // token joined/exited, and the token in which fees will be paid).\n\n // The protocol fee is charged using the token with the highest balance in the pool.\n uint256 chosenTokenIndex = balances[0] > balances[1] ? 0 : 1;\n\n // Set the fee amount to pay in the selected token\n dueProtocolFeeAmounts[chosenTokenIndex] = StableMath._calcDueTokenProtocolSwapFeeAmount(\n _lastInvariantAmp,\n balances,\n _lastInvariant,\n chosenTokenIndex,\n protocolSwapFeePercentage\n );\n\n return dueProtocolFeeAmounts;\n }\n\n /**\n * @dev Computes and stores the value of the invariant after a join, which is required to compute due protocol fees\n * in the future.\n */\n function _updateInvariantAfterJoin(uint256[] memory balances, uint256[] memory amountsIn) private {\n balances.add(amountsIn);\n\n (uint256 currentAmp, ) = _getAmplificationParameter();\n // This invariant is used only to compute the final balance when calculating the protocol fees. These are\n // rounded down, so we round the invariant up.\n _updateLastInvariant(StableMath._calculateInvariant(currentAmp, balances, true), currentAmp);\n }\n\n /**\n * @dev Computes and stores the value of the invariant after an exit, which is required to compute due protocol fees\n * in the future.\n */\n function _updateInvariantAfterExit(uint256[] memory balances, uint256[] memory amountsOut) private {\n balances.sub(amountsOut);\n\n (uint256 currentAmp, ) = _getAmplificationParameter();\n // This invariant is used only to compute the final balance when calculating the protocol fees. These are\n // rounded down, so we round the invariant up.\n _updateLastInvariant(StableMath._calculateInvariant(currentAmp, balances, true), currentAmp);\n }\n\n /// @dev Creates 2 element array of token rates(pricePerFullshare)\n /// @return Array of token rates\n function _getTokenRates() private returns (uint256[] memory) {\n uint256[] memory rates = new uint256[](_TOTAL_TOKENS);\n rates[0] = _token0.getPricePerFullShare();\n // We already did updateInterestRate, so we can use stored values\n rates[1] = _token1.getPricePerFullShareStored();\n return rates;\n }\n\n /// @dev Creates 2 element array of token rates(pricePerFullShareStored)\n /// @return Array of stored token rates\n function _getTokenRatesStored() private view returns (uint256[] memory) {\n uint256[] memory rates = new uint256[](_TOTAL_TOKENS);\n rates[0] = _token0.getPricePerFullShareStored();\n rates[1] = _token1.getPricePerFullShareStored();\n return rates;\n }\n\n function getRate() external view override returns (uint256) {\n (, uint256[] memory balances, ) = getVault().getPoolTokens(getPoolId());\n\n // When calculating the current BPT rate, we may not have paid the protocol fees, therefore\n // the invariant should be smaller than its current value. Then, we round down overall.\n (uint256 currentAmp, ) = _getAmplificationParameter();\n\n _upscaleArray(balances, _scalingFactors());\n\n balances.mul(_getTokenRatesStored(), _TEMPUS_SHARE_PRECISION);\n uint256 invariant = StableMath._calculateInvariant(currentAmp, balances, false);\n return invariant.divDown(totalSupply());\n }\n\n // Amplification\n\n /**\n * @dev Begins changing the amplification parameter to `rawEndValue` over time. The value will change linearly until\n * `endTime` is reached, when it will be `rawEndValue`.\n *\n * NOTE: Internally, the amplification parameter is represented using higher precision. The values returned by\n * `getAmplificationParameter` have to be corrected to account for this when comparing to `rawEndValue`.\n */\n function startAmplificationParameterUpdate(uint256 rawEndValue, uint256 endTime) external authenticate {\n _startAmplificationParameterUpdate(rawEndValue, endTime);\n }\n\n function _startAmplificationParameterUpdate(uint256 rawEndValue, uint256 endTime) private {\n _require(rawEndValue >= _MIN_AMP, Errors.MIN_AMP);\n _require(rawEndValue <= _MAX_AMP, Errors.MAX_AMP);\n\n uint256 duration = Math.sub(endTime, block.timestamp);\n _require(duration >= _MIN_UPDATE_TIME, Errors.AMP_END_TIME_TOO_CLOSE);\n\n (uint256 currentValue, bool isUpdating) = _getAmplificationParameter();\n _require(!isUpdating, Errors.AMP_ONGOING_UPDATE);\n\n uint256 endValue = Math.mul(rawEndValue, _AMP_PRECISION);\n\n // daily rate = (endValue / currentValue) / duration * 1 day\n // We perform all multiplications first to not reduce precision, and round the division up as we want to avoid\n // large rates. Note that these are regular integer multiplications and divisions, not fixed point.\n uint256 dailyRate = endValue > currentValue\n ? Math.divUp(Math.mul(1 days, endValue), Math.mul(currentValue, duration))\n : Math.divUp(Math.mul(1 days, currentValue), Math.mul(endValue, duration));\n _require(dailyRate <= _MAX_AMP_UPDATE_DAILY_RATE, Errors.AMP_RATE_TOO_HIGH);\n\n _setAmplificationData(currentValue, endValue, block.timestamp, endTime);\n }\n\n /**\n * @dev Stops the amplification parameter change process, keeping the current value.\n */\n function stopAmplificationParameterUpdate() external authenticate {\n (uint256 currentValue, bool isUpdating) = _getAmplificationParameter();\n _require(isUpdating, Errors.AMP_NO_ONGOING_UPDATE);\n\n _setAmplificationData(currentValue);\n }\n\n function _isOwnerOnlyAction(bytes32 actionId) internal view virtual override returns (bool) {\n return\n (actionId == getActionId(TempusAMM.startAmplificationParameterUpdate.selector)) ||\n (actionId == getActionId(TempusAMM.stopAmplificationParameterUpdate.selector)) ||\n super._isOwnerOnlyAction(actionId);\n }\n\n function getAmplificationParameter()\n external\n view\n returns (\n uint256 value,\n bool isUpdating,\n uint256 precision\n )\n {\n (value, isUpdating) = _getAmplificationParameter();\n precision = _AMP_PRECISION;\n }\n\n function _getAmplificationParameter() private view returns (uint256 value, bool isUpdating) {\n (uint256 startValue, uint256 endValue, uint256 startTime, uint256 endTime) = _getAmplificationData();\n\n // Note that block.timestamp >= startTime, since startTime is set to the current time when an update starts\n\n if (block.timestamp < endTime) {\n isUpdating = true;\n\n // We can skip checked arithmetic as:\n // - block.timestamp is always larger or equal to startTime\n // - endTime is always larger than startTime\n // - the value delta is bounded by the largest amplification paramater, which never causes the\n // multiplication to overflow.\n // This also means that the following computation will never revert nor yield invalid results.\n if (endValue > startValue) {\n value = startValue + ((endValue - startValue) * (block.timestamp - startTime)) / (endTime - startTime);\n } else {\n value = startValue - ((startValue - endValue) * (block.timestamp - startTime)) / (endTime - startTime);\n }\n } else {\n isUpdating = false;\n value = endValue;\n }\n }\n\n function _getMaxTokens() internal pure override returns (uint256) {\n return _TOTAL_TOKENS;\n }\n\n function _getTotalTokens() internal pure virtual override returns (uint256) {\n return _TOTAL_TOKENS;\n }\n\n function _scalingFactor(IERC20 token) internal view virtual override returns (uint256 scalingFactor) {\n // prettier-ignore\n if (_isToken0(token)) { return _scalingFactor0; }\n else if (_isToken1(token)) { return _scalingFactor1; }\n else {\n _revert(Errors.INVALID_TOKEN);\n }\n }\n\n function _scalingFactors() internal view virtual override returns (uint256[] memory) {\n uint256 totalTokens = _TOTAL_TOKENS;\n uint256[] memory scalingFactors = new uint256[](totalTokens);\n\n // prettier-ignore\n {\n if (totalTokens > 0) { scalingFactors[0] = _scalingFactor0; } else { return scalingFactors; }\n if (totalTokens > 1) { scalingFactors[1] = _scalingFactor1; } else { return scalingFactors; }\n }\n\n return scalingFactors;\n }\n\n function _setAmplificationData(uint256 value) private {\n _setAmplificationData(value, value, block.timestamp, block.timestamp);\n\n emit AmpUpdateStopped(value);\n }\n\n function _setAmplificationData(\n uint256 startValue,\n uint256 endValue,\n uint256 startTime,\n uint256 endTime\n ) private {\n // Here we use inline assembly to save amount of sstores\n // AmplificationData fits one storage slot, so we use inline assembly to update it with only one sstore\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let value := or(or(shl(192, startValue), shl(128, endValue)), or(shl(64, startTime), endTime))\n sstore(_amplificationData.slot, value)\n }\n\n emit AmpUpdateStarted(startValue, endValue, startTime, endTime);\n }\n\n function _getAmplificationData()\n private\n view\n returns (\n uint256 startValue,\n uint256 endValue,\n uint256 startTime,\n uint256 endTime\n )\n {\n // Here we use inline assembly to save amount of sloads\n // AmplificationData fits one storage slot, so we use inline assembly to read it with only one sload\n // solhint-disable-next-line no-inline-assembly\n assembly {\n let mask := 0x000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF\n let value := sload(_amplificationData.slot)\n startValue := and(shr(192, value), mask)\n endValue := and(shr(128, value), mask)\n startTime := and(shr(64, value), mask)\n endTime := and(value, mask)\n }\n }\n\n function _isToken0(IERC20 token) private view returns (bool) {\n return address(token) == address(_token0);\n }\n\n function _isToken1(IERC20 token) private view returns (bool) {\n return address(token) == address(_token1);\n }\n\n function _mapTempusSharesToIERC20(ITempusPool pool) private view returns (IERC20[] memory) {\n IERC20[] memory tokens = new IERC20[](2);\n IPoolShare yieldShare = pool.yieldShare();\n IPoolShare principalShare = pool.principalShare();\n (tokens[0], tokens[1]) = (yieldShare < principalShare)\n ? (IERC20(address(yieldShare)), IERC20(address(principalShare)))\n : (IERC20(address(principalShare)), IERC20(address(yieldShare)));\n return tokens;\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"./LogExpMath.sol\";\nimport \"../helpers/BalancerErrors.sol\";\n\n/* solhint-disable private-vars-leading-underscore */\n\nlibrary FixedPoint {\n uint256 internal constant ONE = 1e18; // 18 decimal places\n uint256 internal constant MAX_POW_RELATIVE_ERROR = 10000; // 10^(-14)\n\n // Minimum base for the power function when the exponent is 'free' (larger than ONE).\n uint256 internal constant MIN_POW_BASE_FREE_EXPONENT = 0.7e18;\n\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n // Fixed Point addition is the same as regular checked addition\n\n uint256 c = a + b;\n _require(c >= a, Errors.ADD_OVERFLOW);\n return c;\n }\n\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n // Fixed Point addition is the same as regular checked addition\n\n _require(b <= a, Errors.SUB_OVERFLOW);\n uint256 c = a - b;\n return c;\n }\n\n function mulDown(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 product = a * b;\n _require(a == 0 || product / a == b, Errors.MUL_OVERFLOW);\n\n return product / ONE;\n }\n\n function mulUp(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 product = a * b;\n _require(a == 0 || product / a == b, Errors.MUL_OVERFLOW);\n\n if (product == 0) {\n return 0;\n } else {\n // The traditional divUp formula is:\n // divUp(x, y) := (x + y - 1) / y\n // To avoid intermediate overflow in the addition, we distribute the division and get:\n // divUp(x, y) := (x - 1) / y + 1\n // Note that this requires x != 0, which we already tested for.\n\n return ((product - 1) / ONE) + 1;\n }\n }\n\n function divDown(uint256 a, uint256 b) internal pure returns (uint256) {\n _require(b != 0, Errors.ZERO_DIVISION);\n\n if (a == 0) {\n return 0;\n } else {\n uint256 aInflated = a * ONE;\n _require(aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow\n\n return aInflated / b;\n }\n }\n\n function divUp(uint256 a, uint256 b) internal pure returns (uint256) {\n _require(b != 0, Errors.ZERO_DIVISION);\n\n if (a == 0) {\n return 0;\n } else {\n uint256 aInflated = a * ONE;\n _require(aInflated / a == ONE, Errors.DIV_INTERNAL); // mul overflow\n\n // The traditional divUp formula is:\n // divUp(x, y) := (x + y - 1) / y\n // To avoid intermediate overflow in the addition, we distribute the division and get:\n // divUp(x, y) := (x - 1) / y + 1\n // Note that this requires x != 0, which we already tested for.\n\n return ((aInflated - 1) / b) + 1;\n }\n }\n\n /**\n * @dev Returns x^y, assuming both are fixed point numbers, rounding down. The result is guaranteed to not be above\n * the true value (that is, the error function expected - actual is always positive).\n */\n function powDown(uint256 x, uint256 y) internal pure returns (uint256) {\n uint256 raw = LogExpMath.pow(x, y);\n uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);\n\n if (raw < maxError) {\n return 0;\n } else {\n return sub(raw, maxError);\n }\n }\n\n /**\n * @dev Returns x^y, assuming both are fixed point numbers, rounding up. The result is guaranteed to not be below\n * the true value (that is, the error function expected - actual is always negative).\n */\n function powUp(uint256 x, uint256 y) internal pure returns (uint256) {\n uint256 raw = LogExpMath.pow(x, y);\n uint256 maxError = add(mulUp(raw, MAX_POW_RELATIVE_ERROR), 1);\n\n return add(raw, maxError);\n }\n\n /**\n * @dev Returns the complement of a value (1 - x), capped to 0 if x is larger than 1.\n *\n * Useful when computing the complement for values with some level of relative error, as it strips this error and\n * prevents intermediate negative values.\n */\n function complement(uint256 x) internal pure returns (uint256) {\n return (x < ONE) ? (ONE - x) : 0;\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/InputHelpers.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"../openzeppelin/IERC20.sol\";\n\nimport \"./BalancerErrors.sol\";\n\nlibrary InputHelpers {\n function ensureInputLengthMatch(uint256 a, uint256 b) internal pure {\n _require(a == b, Errors.INPUT_LENGTH_MISMATCH);\n }\n\n function ensureInputLengthMatch(\n uint256 a,\n uint256 b,\n uint256 c\n ) internal pure {\n _require(a == b && b == c, Errors.INPUT_LENGTH_MISMATCH);\n }\n\n function ensureArrayIsSorted(IERC20[] memory array) internal pure {\n address[] memory addressArray;\n // solhint-disable-next-line no-inline-assembly\n assembly {\n addressArray := array\n }\n ensureArrayIsSorted(addressArray);\n }\n\n function ensureArrayIsSorted(address[] memory array) internal pure {\n if (array.length < 2) {\n return;\n }\n\n address previous = array[0];\n for (uint256 i = 1; i < array.length; ++i) {\n address current = array[i];\n _require(previous < current, Errors.UNSORTED_ARRAY);\n previous = current;\n }\n }\n}\n"
- },
- "@balancer-labs/v2-pool-utils/contracts/BaseGeneralPool.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"./BasePool.sol\";\nimport \"@balancer-labs/v2-vault/contracts/interfaces/IGeneralPool.sol\";\n\n/**\n * @dev Extension of `BasePool`, adding a handler for `IGeneralPool.onSwap`.\n *\n * Derived contracts must call `BasePool`'s constructor, and implement `_onSwapGivenIn` and `_onSwapGivenOut` along with\n * `BasePool`'s virtual functions. Inheriting from this contract lets derived contracts choose the General\n * specialization setting.\n */\nabstract contract BaseGeneralPool is IGeneralPool, BasePool {\n // Swap Hooks\n\n function onSwap(\n SwapRequest memory swapRequest,\n uint256[] memory balances,\n uint256 indexIn,\n uint256 indexOut\n ) public virtual override returns (uint256) {\n _validateIndexes(indexIn, indexOut, _getTotalTokens());\n uint256[] memory scalingFactors = _scalingFactors();\n\n return\n swapRequest.kind == IVault.SwapKind.GIVEN_IN\n ? _swapGivenIn(swapRequest, balances, indexIn, indexOut, scalingFactors)\n : _swapGivenOut(swapRequest, balances, indexIn, indexOut, scalingFactors);\n }\n\n function _swapGivenIn(\n SwapRequest memory swapRequest,\n uint256[] memory balances,\n uint256 indexIn,\n uint256 indexOut,\n uint256[] memory scalingFactors\n ) internal returns (uint256) {\n // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis.\n swapRequest.amount = _subtractSwapFeeAmount(swapRequest.amount);\n\n _upscaleArray(balances, scalingFactors);\n swapRequest.amount = _upscale(swapRequest.amount, scalingFactors[indexIn]);\n\n uint256 amountOut = _onSwapGivenIn(swapRequest, balances, indexIn, indexOut);\n\n // amountOut tokens are exiting the Pool, so we round down.\n return _downscaleDown(amountOut, scalingFactors[indexOut]);\n }\n\n function _swapGivenOut(\n SwapRequest memory swapRequest,\n uint256[] memory balances,\n uint256 indexIn,\n uint256 indexOut,\n uint256[] memory scalingFactors\n ) internal returns (uint256) {\n _upscaleArray(balances, scalingFactors);\n swapRequest.amount = _upscale(swapRequest.amount, scalingFactors[indexOut]);\n\n uint256 amountIn = _onSwapGivenOut(swapRequest, balances, indexIn, indexOut);\n\n // amountIn tokens are entering the Pool, so we round up.\n amountIn = _downscaleUp(amountIn, scalingFactors[indexIn]);\n\n // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis.\n return _addSwapFeeAmount(amountIn);\n }\n\n /*\n * @dev Called when a swap with the Pool occurs, where the amount of tokens entering the Pool is known.\n *\n * Returns the amount of tokens that will be taken from the Pool in return.\n *\n * All amounts inside `swapRequest` and `balances` are upscaled. The swap fee has already been deducted from\n * `swapRequest.amount`.\n *\n * The return value is also considered upscaled, and will be downscaled (rounding down) before returning it to the\n * Vault.\n */\n function _onSwapGivenIn(\n SwapRequest memory swapRequest,\n uint256[] memory balances,\n uint256 indexIn,\n uint256 indexOut\n ) internal virtual returns (uint256);\n\n /*\n * @dev Called when a swap with the Pool occurs, where the amount of tokens exiting the Pool is known.\n *\n * Returns the amount of tokens that will be granted to the Pool in return.\n *\n * All amounts inside `swapRequest` and `balances` are upscaled.\n *\n * The return value is also considered upscaled, and will be downscaled (rounding up) before applying the swap fee\n * and returning it to the Vault.\n */\n function _onSwapGivenOut(\n SwapRequest memory swapRequest,\n uint256[] memory balances,\n uint256 indexIn,\n uint256 indexOut\n ) internal virtual returns (uint256);\n\n function _validateIndexes(\n uint256 indexIn,\n uint256 indexOut,\n uint256 limit\n ) private pure {\n _require(indexIn < limit && indexOut < limit, Errors.OUT_OF_BOUNDS);\n }\n}\n"
- },
- "@balancer-labs/v2-pool-utils/contracts/BaseMinimalSwapInfoPool.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"./BasePool.sol\";\nimport \"@balancer-labs/v2-vault/contracts/interfaces/IMinimalSwapInfoPool.sol\";\n\n/**\n * @dev Extension of `BasePool`, adding a handler for `IMinimalSwapInfoPool.onSwap`.\n *\n * Derived contracts must call `BasePool`'s constructor, and implement `_onSwapGivenIn` and `_onSwapGivenOut` along with\n * `BasePool`'s virtual functions. Inheriting from this contract lets derived contracts choose the Two Token or Minimal\n * Swap Info specialization settings.\n */\nabstract contract BaseMinimalSwapInfoPool is IMinimalSwapInfoPool, BasePool {\n // Swap Hooks\n\n function onSwap(\n SwapRequest memory request,\n uint256 balanceTokenIn,\n uint256 balanceTokenOut\n ) public virtual override returns (uint256) {\n uint256 scalingFactorTokenIn = _scalingFactor(request.tokenIn);\n uint256 scalingFactorTokenOut = _scalingFactor(request.tokenOut);\n\n if (request.kind == IVault.SwapKind.GIVEN_IN) {\n // Fees are subtracted before scaling, to reduce the complexity of the rounding direction analysis.\n request.amount = _subtractSwapFeeAmount(request.amount);\n\n // All token amounts are upscaled.\n balanceTokenIn = _upscale(balanceTokenIn, scalingFactorTokenIn);\n balanceTokenOut = _upscale(balanceTokenOut, scalingFactorTokenOut);\n request.amount = _upscale(request.amount, scalingFactorTokenIn);\n\n uint256 amountOut = _onSwapGivenIn(request, balanceTokenIn, balanceTokenOut);\n\n // amountOut tokens are exiting the Pool, so we round down.\n return _downscaleDown(amountOut, scalingFactorTokenOut);\n } else {\n // All token amounts are upscaled.\n balanceTokenIn = _upscale(balanceTokenIn, scalingFactorTokenIn);\n balanceTokenOut = _upscale(balanceTokenOut, scalingFactorTokenOut);\n request.amount = _upscale(request.amount, scalingFactorTokenOut);\n\n uint256 amountIn = _onSwapGivenOut(request, balanceTokenIn, balanceTokenOut);\n\n // amountIn tokens are entering the Pool, so we round up.\n amountIn = _downscaleUp(amountIn, scalingFactorTokenIn);\n\n // Fees are added after scaling happens, to reduce the complexity of the rounding direction analysis.\n return _addSwapFeeAmount(amountIn);\n }\n }\n\n /*\n * @dev Called when a swap with the Pool occurs, where the amount of tokens entering the Pool is known.\n *\n * Returns the amount of tokens that will be taken from the Pool in return.\n *\n * All amounts inside `swapRequest`, `balanceTokenIn` and `balanceTokenOut` are upscaled. The swap fee has already\n * been deducted from `swapRequest.amount`.\n *\n * The return value is also considered upscaled, and will be downscaled (rounding down) before returning it to the\n * Vault.\n */\n function _onSwapGivenIn(\n SwapRequest memory swapRequest,\n uint256 balanceTokenIn,\n uint256 balanceTokenOut\n ) internal virtual returns (uint256);\n\n /*\n * @dev Called when a swap with the Pool occurs, where the amount of tokens exiting the Pool is known.\n *\n * Returns the amount of tokens that will be granted to the Pool in return.\n *\n * All amounts inside `swapRequest`, `balanceTokenIn` and `balanceTokenOut` are upscaled.\n *\n * The return value is also considered upscaled, and will be downscaled (rounding up) before applying the swap fee\n * and returning it to the Vault.\n */\n function _onSwapGivenOut(\n SwapRequest memory swapRequest,\n uint256 balanceTokenIn,\n uint256 balanceTokenOut\n ) internal virtual returns (uint256);\n}\n"
- },
- "@balancer-labs/v2-pool-stable/contracts/StableMath.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/math/Math.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol\";\n\n// This is a contract to emulate file-level functions. Convert to a library\n// after the migration to solc v0.7.1.\n\n// solhint-disable private-vars-leading-underscore\n// solhint-disable var-name-mixedcase\n\ncontract StableMath {\n using FixedPoint for uint256;\n\n uint256 internal constant _MIN_AMP = 1;\n uint256 internal constant _MAX_AMP = 5000;\n uint256 internal constant _AMP_PRECISION = 1e3;\n\n uint256 internal constant _MAX_STABLE_TOKENS = 5;\n\n // Note on unchecked arithmetic:\n // This contract performs a large number of additions, subtractions, multiplications and divisions, often inside\n // loops. Since many of these operations are gas-sensitive (as they happen e.g. during a swap), it is important to\n // not make any unnecessary checks. We rely on a set of invariants to avoid having to use checked arithmetic (the\n // Math library), including:\n // - the number of tokens is bounded by _MAX_STABLE_TOKENS\n // - the amplification parameter is bounded by _MAX_AMP * _AMP_PRECISION, which fits in 23 bits\n // - the token balances are bounded by 2^112 (guaranteed by the Vault) times 1e18 (the maximum scaling factor),\n // which fits in 172 bits\n //\n // This means e.g. we can safely multiply a balance by the amplification parameter without worrying about overflow.\n\n // Computes the invariant given the current balances, using the Newton-Raphson approximation.\n // The amplification parameter equals: A n^(n-1)\n function _calculateInvariant(\n uint256 amplificationParameter,\n uint256[] memory balances,\n bool roundUp\n ) internal pure returns (uint256) {\n /**********************************************************************************************\n // invariant //\n // D = invariant D^(n+1) //\n // A = amplification coefficient A n^n S + D = A D n^n + ----------- //\n // S = sum of balances n^n P //\n // P = product of balances //\n // n = number of tokens //\n *********x************************************************************************************/\n\n // We support rounding up or down.\n\n uint256 sum = 0;\n uint256 numTokens = balances.length;\n for (uint256 i = 0; i < numTokens; i++) {\n sum = sum.add(balances[i]);\n }\n if (sum == 0) {\n return 0;\n }\n\n uint256 prevInvariant = 0;\n uint256 invariant = sum;\n uint256 ampTimesTotal = amplificationParameter * numTokens;\n\n for (uint256 i = 0; i < 255; i++) {\n uint256 P_D = balances[0] * numTokens;\n for (uint256 j = 1; j < numTokens; j++) {\n P_D = Math.div(Math.mul(Math.mul(P_D, balances[j]), numTokens), invariant, roundUp);\n }\n prevInvariant = invariant;\n invariant = Math.div(\n Math.mul(Math.mul(numTokens, invariant), invariant).add(\n Math.div(Math.mul(Math.mul(ampTimesTotal, sum), P_D), _AMP_PRECISION, roundUp)\n ),\n Math.mul(numTokens + 1, invariant).add(\n // No need to use checked arithmetic for the amp precision, the amp is guaranteed to be at least 1\n Math.div(Math.mul(ampTimesTotal - _AMP_PRECISION, P_D), _AMP_PRECISION, !roundUp)\n ),\n roundUp\n );\n\n if (invariant > prevInvariant) {\n if (invariant - prevInvariant <= 1) {\n return invariant;\n }\n } else if (prevInvariant - invariant <= 1) {\n return invariant;\n }\n }\n\n _revert(Errors.STABLE_GET_BALANCE_DIDNT_CONVERGE);\n }\n\n // Computes how many tokens can be taken out of a pool if `tokenAmountIn` are sent, given the current balances.\n // The amplification parameter equals: A n^(n-1)\n function _calcOutGivenIn(\n uint256 amplificationParameter,\n uint256[] memory balances,\n uint256 tokenIndexIn,\n uint256 tokenIndexOut,\n uint256 tokenAmountIn\n ) internal pure returns (uint256) {\n /**************************************************************************************************************\n // outGivenIn token x for y - polynomial equation to solve //\n // ay = amount out to calculate //\n // by = balance token out //\n // y = by - ay (finalBalanceOut) //\n // D = invariant D D^(n+1) //\n // A = amplification coefficient y^2 + ( S - ---------- - D) * y - ------------- = 0 //\n // n = number of tokens (A * n^n) A * n^2n * P //\n // S = sum of final balances but y //\n // P = product of final balances but y //\n **************************************************************************************************************/\n\n // Amount out, so we round down overall.\n\n // Given that we need to have a greater final balance out, the invariant needs to be rounded up\n uint256 invariant = _calculateInvariant(amplificationParameter, balances, true);\n\n balances[tokenIndexIn] = balances[tokenIndexIn].add(tokenAmountIn);\n\n uint256 finalBalanceOut = _getTokenBalanceGivenInvariantAndAllOtherBalances(\n amplificationParameter,\n balances,\n invariant,\n tokenIndexOut\n );\n\n // No need to use checked arithmetic since `tokenAmountIn` was actually added to the same balance right before\n // calling `_getTokenBalanceGivenInvariantAndAllOtherBalances` which doesn't alter the balances array.\n balances[tokenIndexIn] = balances[tokenIndexIn] - tokenAmountIn;\n\n return balances[tokenIndexOut].sub(finalBalanceOut).sub(1);\n }\n\n // Computes how many tokens must be sent to a pool if `tokenAmountOut` are sent given the\n // current balances, using the Newton-Raphson approximation.\n // The amplification parameter equals: A n^(n-1)\n function _calcInGivenOut(\n uint256 amplificationParameter,\n uint256[] memory balances,\n uint256 tokenIndexIn,\n uint256 tokenIndexOut,\n uint256 tokenAmountOut\n ) internal pure returns (uint256) {\n /**************************************************************************************************************\n // inGivenOut token x for y - polynomial equation to solve //\n // ax = amount in to calculate //\n // bx = balance token in //\n // x = bx + ax (finalBalanceIn) //\n // D = invariant D D^(n+1) //\n // A = amplification coefficient x^2 + ( S - ---------- - D) * x - ------------- = 0 //\n // n = number of tokens (A * n^n) A * n^2n * P //\n // S = sum of final balances but x //\n // P = product of final balances but x //\n **************************************************************************************************************/\n\n // Amount in, so we round up overall.\n\n // Given that we need to have a greater final balance in, the invariant needs to be rounded up\n uint256 invariant = _calculateInvariant(amplificationParameter, balances, true);\n\n balances[tokenIndexOut] = balances[tokenIndexOut].sub(tokenAmountOut);\n\n uint256 finalBalanceIn = _getTokenBalanceGivenInvariantAndAllOtherBalances(\n amplificationParameter,\n balances,\n invariant,\n tokenIndexIn\n );\n\n // No need to use checked arithmetic since `tokenAmountOut` was actually subtracted from the same balance right\n // before calling `_getTokenBalanceGivenInvariantAndAllOtherBalances` which doesn't alter the balances array.\n balances[tokenIndexOut] = balances[tokenIndexOut] + tokenAmountOut;\n\n return finalBalanceIn.sub(balances[tokenIndexIn]).add(1);\n }\n\n function _calcBptOutGivenExactTokensIn(\n uint256 amp,\n uint256[] memory balances,\n uint256[] memory amountsIn,\n uint256 bptTotalSupply,\n uint256 swapFeePercentage\n ) internal pure returns (uint256) {\n // BPT out, so we round down overall.\n\n // First loop calculates the sum of all token balances, which will be used to calculate\n // the current weights of each token, relative to this sum\n uint256 sumBalances = 0;\n for (uint256 i = 0; i < balances.length; i++) {\n sumBalances = sumBalances.add(balances[i]);\n }\n\n // Calculate the weighted balance ratio without considering fees\n uint256[] memory balanceRatiosWithFee = new uint256[](amountsIn.length);\n // The weighted sum of token balance ratios without fee\n uint256 invariantRatioWithFees = 0;\n for (uint256 i = 0; i < balances.length; i++) {\n uint256 currentWeight = balances[i].divDown(sumBalances);\n balanceRatiosWithFee[i] = balances[i].add(amountsIn[i]).divDown(balances[i]);\n invariantRatioWithFees = invariantRatioWithFees.add(balanceRatiosWithFee[i].mulDown(currentWeight));\n }\n\n // Second loop calculates new amounts in, taking into account the fee on the percentage excess\n uint256[] memory newBalances = new uint256[](balances.length);\n for (uint256 i = 0; i < balances.length; i++) {\n uint256 amountInWithoutFee;\n\n // Check if the balance ratio is greater than the ideal ratio to charge fees or not\n if (balanceRatiosWithFee[i] > invariantRatioWithFees) {\n uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithFees.sub(FixedPoint.ONE));\n uint256 taxableAmount = amountsIn[i].sub(nonTaxableAmount);\n // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%\n amountInWithoutFee = nonTaxableAmount.add(taxableAmount.mulDown(FixedPoint.ONE - swapFeePercentage));\n } else {\n amountInWithoutFee = amountsIn[i];\n }\n\n newBalances[i] = balances[i].add(amountInWithoutFee);\n }\n\n // Get current and new invariants, taking swap fees into account\n uint256 currentInvariant = _calculateInvariant(amp, balances, true);\n uint256 newInvariant = _calculateInvariant(amp, newBalances, false);\n uint256 invariantRatio = newInvariant.divDown(currentInvariant);\n\n // If the invariant didn't increase for any reason, we simply don't mint BPT\n if (invariantRatio > FixedPoint.ONE) {\n return bptTotalSupply.mulDown(invariantRatio - FixedPoint.ONE);\n } else {\n return 0;\n }\n }\n\n function _calcTokenInGivenExactBptOut(\n uint256 amp,\n uint256[] memory balances,\n uint256 tokenIndex,\n uint256 bptAmountOut,\n uint256 bptTotalSupply,\n uint256 swapFeePercentage\n ) internal pure returns (uint256) {\n // Token in, so we round up overall.\n\n // Get the current invariant\n uint256 currentInvariant = _calculateInvariant(amp, balances, true);\n\n // Calculate new invariant\n uint256 newInvariant = bptTotalSupply.add(bptAmountOut).divUp(bptTotalSupply).mulUp(currentInvariant);\n\n // Calculate amount in without fee.\n uint256 newBalanceTokenIndex = _getTokenBalanceGivenInvariantAndAllOtherBalances(\n amp,\n balances,\n newInvariant,\n tokenIndex\n );\n uint256 amountInWithoutFee = newBalanceTokenIndex.sub(balances[tokenIndex]);\n\n // First calculate the sum of all token balances, which will be used to calculate\n // the current weight of each token\n uint256 sumBalances = 0;\n for (uint256 i = 0; i < balances.length; i++) {\n sumBalances = sumBalances.add(balances[i]);\n }\n\n // We can now compute how much extra balance is being deposited and used in virtual swaps, and charge swap fees\n // accordingly.\n uint256 currentWeight = balances[tokenIndex].divDown(sumBalances);\n uint256 taxablePercentage = currentWeight.complement();\n uint256 taxableAmount = amountInWithoutFee.mulUp(taxablePercentage);\n uint256 nonTaxableAmount = amountInWithoutFee.sub(taxableAmount);\n\n // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%\n return nonTaxableAmount.add(taxableAmount.divUp(FixedPoint.ONE - swapFeePercentage));\n }\n\n /*\n Flow of calculations:\n amountsTokenOut -> amountsOutProportional ->\n amountOutPercentageExcess -> amountOutBeforeFee -> newInvariant -> amountBPTIn\n */\n function _calcBptInGivenExactTokensOut(\n uint256 amp,\n uint256[] memory balances,\n uint256[] memory amountsOut,\n uint256 bptTotalSupply,\n uint256 swapFeePercentage\n ) internal pure returns (uint256) {\n // BPT in, so we round up overall.\n\n // First loop calculates the sum of all token balances, which will be used to calculate\n // the current weights of each token relative to this sum\n uint256 sumBalances = 0;\n for (uint256 i = 0; i < balances.length; i++) {\n sumBalances = sumBalances.add(balances[i]);\n }\n\n // Calculate the weighted balance ratio without considering fees\n uint256[] memory balanceRatiosWithoutFee = new uint256[](amountsOut.length);\n uint256 invariantRatioWithoutFees = 0;\n for (uint256 i = 0; i < balances.length; i++) {\n uint256 currentWeight = balances[i].divUp(sumBalances);\n balanceRatiosWithoutFee[i] = balances[i].sub(amountsOut[i]).divUp(balances[i]);\n invariantRatioWithoutFees = invariantRatioWithoutFees.add(balanceRatiosWithoutFee[i].mulUp(currentWeight));\n }\n\n // Second loop calculates new amounts in, taking into account the fee on the percentage excess\n uint256[] memory newBalances = new uint256[](balances.length);\n for (uint256 i = 0; i < balances.length; i++) {\n // Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it to\n // 'token out'. This results in slightly larger price impact.\n\n uint256 amountOutWithFee;\n if (invariantRatioWithoutFees > balanceRatiosWithoutFee[i]) {\n uint256 nonTaxableAmount = balances[i].mulDown(invariantRatioWithoutFees.complement());\n uint256 taxableAmount = amountsOut[i].sub(nonTaxableAmount);\n // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%\n amountOutWithFee = nonTaxableAmount.add(taxableAmount.divUp(FixedPoint.ONE - swapFeePercentage));\n } else {\n amountOutWithFee = amountsOut[i];\n }\n\n newBalances[i] = balances[i].sub(amountOutWithFee);\n }\n\n // Get current and new invariants, taking into account swap fees\n uint256 currentInvariant = _calculateInvariant(amp, balances, true);\n uint256 newInvariant = _calculateInvariant(amp, newBalances, false);\n uint256 invariantRatio = newInvariant.divDown(currentInvariant);\n\n // return amountBPTIn\n return bptTotalSupply.mulUp(invariantRatio.complement());\n }\n\n function _calcTokenOutGivenExactBptIn(\n uint256 amp,\n uint256[] memory balances,\n uint256 tokenIndex,\n uint256 bptAmountIn,\n uint256 bptTotalSupply,\n uint256 swapFeePercentage\n ) internal pure returns (uint256) {\n // Token out, so we round down overall.\n\n // Get the current and new invariants. Since we need a bigger new invariant, we round the current one up.\n uint256 currentInvariant = _calculateInvariant(amp, balances, true);\n uint256 newInvariant = bptTotalSupply.sub(bptAmountIn).divUp(bptTotalSupply).mulUp(currentInvariant);\n\n // Calculate amount out without fee\n uint256 newBalanceTokenIndex = _getTokenBalanceGivenInvariantAndAllOtherBalances(\n amp,\n balances,\n newInvariant,\n tokenIndex\n );\n uint256 amountOutWithoutFee = balances[tokenIndex].sub(newBalanceTokenIndex);\n\n // First calculate the sum of all token balances, which will be used to calculate\n // the current weight of each token\n uint256 sumBalances = 0;\n for (uint256 i = 0; i < balances.length; i++) {\n sumBalances = sumBalances.add(balances[i]);\n }\n\n // We can now compute how much excess balance is being withdrawn as a result of the virtual swaps, which result\n // in swap fees.\n uint256 currentWeight = balances[tokenIndex].divDown(sumBalances);\n uint256 taxablePercentage = currentWeight.complement();\n\n // Swap fees are typically charged on 'token in', but there is no 'token in' here, so we apply it\n // to 'token out'. This results in slightly larger price impact. Fees are rounded up.\n uint256 taxableAmount = amountOutWithoutFee.mulUp(taxablePercentage);\n uint256 nonTaxableAmount = amountOutWithoutFee.sub(taxableAmount);\n\n // No need to use checked arithmetic for the swap fee, it is guaranteed to be lower than 50%\n return nonTaxableAmount.add(taxableAmount.mulDown(FixedPoint.ONE - swapFeePercentage));\n }\n\n function _calcTokensOutGivenExactBptIn(\n uint256[] memory balances,\n uint256 bptAmountIn,\n uint256 bptTotalSupply\n ) internal pure returns (uint256[] memory) {\n /**********************************************************************************************\n // exactBPTInForTokensOut //\n // (per token) //\n // aO = tokenAmountOut / bptIn \\ //\n // b = tokenBalance a0 = b * | --------------------- | //\n // bptIn = bptAmountIn \\ bptTotalSupply / //\n // bpt = bptTotalSupply //\n **********************************************************************************************/\n\n // Since we're computing an amount out, we round down overall. This means rounding down on both the\n // multiplication and division.\n\n uint256 bptRatio = bptAmountIn.divDown(bptTotalSupply);\n\n uint256[] memory amountsOut = new uint256[](balances.length);\n for (uint256 i = 0; i < balances.length; i++) {\n amountsOut[i] = balances[i].mulDown(bptRatio);\n }\n\n return amountsOut;\n }\n\n // The amplification parameter equals: A n^(n-1)\n function _calcDueTokenProtocolSwapFeeAmount(\n uint256 amplificationParameter,\n uint256[] memory balances,\n uint256 lastInvariant,\n uint256 tokenIndex,\n uint256 protocolSwapFeePercentage\n ) internal pure returns (uint256) {\n /**************************************************************************************************************\n // oneTokenSwapFee - polynomial equation to solve //\n // af = fee amount to calculate in one token //\n // bf = balance of fee token //\n // f = bf - af (finalBalanceFeeToken) //\n // D = old invariant D D^(n+1) //\n // A = amplification coefficient f^2 + ( S - ---------- - D) * f - ------------- = 0 //\n // n = number of tokens (A * n^n) A * n^2n * P //\n // S = sum of final balances but f //\n // P = product of final balances but f //\n **************************************************************************************************************/\n\n // Protocol swap fee amount, so we round down overall.\n\n uint256 finalBalanceFeeToken = _getTokenBalanceGivenInvariantAndAllOtherBalances(\n amplificationParameter,\n balances,\n lastInvariant,\n tokenIndex\n );\n\n if (balances[tokenIndex] <= finalBalanceFeeToken) {\n // This shouldn't happen outside of rounding errors, but have this safeguard nonetheless to prevent the Pool\n // from entering a locked state in which joins and exits revert while computing accumulated swap fees.\n return 0;\n }\n\n // Result is rounded down\n uint256 accumulatedTokenSwapFees = balances[tokenIndex] - finalBalanceFeeToken;\n return accumulatedTokenSwapFees.mulDown(protocolSwapFeePercentage).divDown(FixedPoint.ONE);\n }\n\n // Private functions\n\n // This function calculates the balance of a given token (tokenIndex)\n // given all the other balances and the invariant\n function _getTokenBalanceGivenInvariantAndAllOtherBalances(\n uint256 amplificationParameter,\n uint256[] memory balances,\n uint256 invariant,\n uint256 tokenIndex\n ) internal pure returns (uint256) {\n // Rounds result up overall\n\n uint256 ampTimesTotal = amplificationParameter * balances.length;\n uint256 sum = balances[0];\n uint256 P_D = balances[0] * balances.length;\n for (uint256 j = 1; j < balances.length; j++) {\n P_D = Math.divDown(Math.mul(Math.mul(P_D, balances[j]), balances.length), invariant);\n sum = sum.add(balances[j]);\n }\n // No need to use safe math, based on the loop above `sum` is greater than or equal to `balances[tokenIndex]`\n sum = sum - balances[tokenIndex];\n\n uint256 inv2 = Math.mul(invariant, invariant);\n // We remove the balance fromm c by multiplying it\n uint256 c = Math.mul(\n Math.mul(Math.divUp(inv2, Math.mul(ampTimesTotal, P_D)), _AMP_PRECISION),\n balances[tokenIndex]\n );\n uint256 b = sum.add(Math.mul(Math.divDown(invariant, ampTimesTotal), _AMP_PRECISION));\n\n // We iterate to find the balance\n uint256 prevTokenBalance = 0;\n // We multiply the first iteration outside the loop with the invariant to set the value of the\n // initial approximation.\n uint256 tokenBalance = Math.divUp(inv2.add(c), invariant.add(b));\n\n for (uint256 i = 0; i < 255; i++) {\n prevTokenBalance = tokenBalance;\n\n tokenBalance = Math.divUp(\n Math.mul(tokenBalance, tokenBalance).add(c),\n Math.mul(tokenBalance, 2).add(b).sub(invariant)\n );\n\n if (tokenBalance > prevTokenBalance) {\n if (tokenBalance - prevTokenBalance <= 1) {\n return tokenBalance;\n }\n } else if (prevTokenBalance - tokenBalance <= 1) {\n return tokenBalance;\n }\n }\n\n _revert(Errors.STABLE_GET_BALANCE_DIDNT_CONVERGE);\n }\n}\n"
- },
- "contracts/amm/interfaces/IRateProvider.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\ninterface IRateProvider {\n function getRate() external view returns (uint256);\n}\n"
- },
- "contracts/ITempusPool.sol": {
- "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.7.6 <0.9.0;\npragma abicoder v2;\n\nimport \"./token/IPoolShare.sol\";\nimport \"./utils/IOwnable.sol\";\nimport \"./utils/IVersioned.sol\";\n\n/// Setting and transferring of fees are restricted to the owner.\ninterface ITempusFees is IOwnable {\n /// The fees are in terms of yield bearing token (YBT).\n struct FeesConfig {\n uint256 depositPercent;\n uint256 earlyRedeemPercent;\n uint256 matureRedeemPercent;\n }\n\n /// Returns the current fee configuration.\n function getFeesConfig() external view returns (FeesConfig memory);\n\n /// Replace the current fee configuration with a new one.\n /// By default all the fees are expected to be set to zero.\n /// @notice This function can only be called by the owner.\n function setFeesConfig(FeesConfig calldata newFeesConfig) external;\n\n /// @return Maximum possible fee percentage that can be set for deposit\n function maxDepositFee() external view returns (uint256);\n\n /// @return Maximum possible fee percentage that can be set for early redeem\n function maxEarlyRedeemFee() external view returns (uint256);\n\n /// @return Maximum possible fee percentage that can be set for mature redeem\n function maxMatureRedeemFee() external view returns (uint256);\n\n /// Accumulated fees available for withdrawal.\n function totalFees() external view returns (uint256);\n\n /// Transfers accumulated Yield Bearing Token (YBT) fees\n /// from this pool contract to `recipient`.\n /// @param recipient Address which will receive the specified amount of YBT\n /// @notice This function can only be called by the owner.\n function transferFees(address recipient) external;\n}\n\n/// All state changing operations are restricted to the controller.\ninterface ITempusPool is ITempusFees, IVersioned {\n /// @return The name of underlying protocol, for example \"Aave\" for Aave protocol\n function protocolName() external view returns (bytes32);\n\n /// This token will be used as a token that user can deposit to mint same amounts\n /// of principal and interest shares.\n /// @return The underlying yield bearing token.\n function yieldBearingToken() external view returns (address);\n\n /// This is the address of the actual backing asset token\n /// in the case of ETH, this address will be 0\n /// @return Address of the Backing Token\n function backingToken() external view returns (address);\n\n /// @return uint256 value of one backing token, in case of 18 decimals 1e18\n function backingTokenONE() external view returns (uint256);\n\n /// @return This TempusPool's Tempus Principal Share (TPS)\n function principalShare() external view returns (IPoolShare);\n\n /// @return This TempusPool's Tempus Yield Share (TYS)\n function yieldShare() external view returns (IPoolShare);\n\n /// @return The TempusController address that is authorized to perform restricted actions\n function controller() external view returns (address);\n\n /// @return Start time of the pool.\n function startTime() external view returns (uint256);\n\n /// @return Maturity time of the pool.\n function maturityTime() external view returns (uint256);\n\n /// @return Time of exceptional halting of the pool.\n /// In case the pool is still in operation, this must return type(uint256).max.\n function exceptionalHaltTime() external view returns (uint256);\n\n /// @return The maximum allowed time (in seconds) to pass with negative yield.\n function maximumNegativeYieldDuration() external view returns (uint256);\n\n /// @return True if maturity has been reached and the pool was finalized.\n /// This also includes the case when maturity was triggered due to\n /// exceptional conditions (negative yield periods).\n function matured() external view returns (bool);\n\n /// Finalizes the pool. This can only happen on or after `maturityTime`.\n /// Once finalized depositing is not possible anymore, and the behaviour\n /// redemption will change.\n ///\n /// Can be called by anyone and can be called multiple times.\n function finalize() external;\n\n /// Yield bearing tokens deposit hook.\n /// @notice Deposit will fail if maturity has been reached.\n /// @notice This function can only be called by TempusController\n /// @notice This function assumes funds were already transferred to the TempusPool from the TempusController\n /// @param yieldTokenAmount Amount of yield bearing tokens to deposit in YieldToken decimal precision\n /// @param recipient Address which will receive Tempus Principal Shares (TPS) and Tempus Yield Shares (TYS)\n /// @return mintedShares Amount of TPS and TYS minted to `recipient`\n /// @return depositedBT The YBT value deposited, denominated as Backing Tokens\n /// @return fee The fee which was deducted (in terms of YBT)\n /// @return rate The interest rate at the time of the deposit\n function onDepositYieldBearing(uint256 yieldTokenAmount, address recipient)\n external\n returns (\n uint256 mintedShares,\n uint256 depositedBT,\n uint256 fee,\n uint256 rate\n );\n\n /// Backing tokens deposit hook.\n /// @notice Deposit will fail if maturity has been reached.\n /// @notice This function can only be called by TempusController\n /// @notice This function assumes funds were already transferred to the TempusPool from the TempusController\n /// @param backingTokenAmount amount of Backing Tokens to be deposited to underlying protocol in BackingToken decimal precision\n /// @param recipient Address which will receive Tempus Principal Shares (TPS) and Tempus Yield Shares (TYS)\n /// @return mintedShares Amount of TPS and TYS minted to `recipient`\n /// @return depositedYBT The BT value deposited, denominated as Yield Bearing Tokens\n /// @return fee The fee which was deducted (in terms of YBT)\n /// @return rate The interest rate at the time of the deposit\n function onDepositBacking(uint256 backingTokenAmount, address recipient)\n external\n payable\n returns (\n uint256 mintedShares,\n uint256 depositedYBT,\n uint256 fee,\n uint256 rate\n );\n\n /// Redeems yield bearing tokens from this TempusPool\n /// msg.sender will receive the YBT\n /// NOTE #1 Before maturity, principalAmount must equal to yieldAmount.\n /// NOTE #2 This function can only be called by TempusController\n /// @param from Address to redeem its Tempus Shares\n /// @param principalAmount Amount of Tempus Principal Shares (TPS) to redeem for YBT in PrincipalShare decimal precision\n /// @param yieldAmount Amount of Tempus Yield Shares (TYS) to redeem for YBT in YieldShare decimal precision\n /// @param recipient Address to which redeemed YBT will be sent\n /// @return redeemableYieldTokens Amount of Yield Bearing Tokens redeemed to `recipient`\n /// @return fee The fee which was deducted (in terms of YBT)\n /// @return rate The interest rate at the time of the redemption\n function redeem(\n address from,\n uint256 principalAmount,\n uint256 yieldAmount,\n address recipient\n )\n external\n returns (\n uint256 redeemableYieldTokens,\n uint256 fee,\n uint256 rate\n );\n\n /// Redeems TPS+TYS held by msg.sender into backing tokens\n /// `msg.sender` must approve TPS and TYS amounts to this TempusPool.\n /// `msg.sender` will receive the backing tokens\n /// NOTE #1 Before maturity, principalAmount must equal to yieldAmount.\n /// NOTE #2 This function can only be called by TempusController\n /// @param from Address to redeem its Tempus Shares\n /// @param principalAmount Amount of Tempus Principal Shares (TPS) to redeem in PrincipalShare decimal precision\n /// @param yieldAmount Amount of Tempus Yield Shares (TYS) to redeem in YieldShare decimal precision\n /// @param recipient Address to which redeemed BT will be sent\n /// @return redeemableYieldTokens Amount of Backing Tokens redeemed to `recipient`, denominated in YBT\n /// @return redeemableBackingTokens Amount of Backing Tokens redeemed to `recipient`\n /// @return fee The fee which was deducted (in terms of YBT)\n /// @return rate The interest rate at the time of the redemption\n function redeemToBacking(\n address from,\n uint256 principalAmount,\n uint256 yieldAmount,\n address recipient\n )\n external\n payable\n returns (\n uint256 redeemableYieldTokens,\n uint256 redeemableBackingTokens,\n uint256 fee,\n uint256 rate\n );\n\n /// Gets the estimated amount of Principals and Yields after a successful deposit\n /// @param amount Amount of BackingTokens or YieldBearingTokens that would be deposited\n /// @param isBackingToken If true, @param amount is in BackingTokens, otherwise YieldBearingTokens\n /// @return Amount of Principals (TPS) and Yields (TYS) in Principal/YieldShare decimal precision\n /// TPS and TYS are minted in 1:1 ratio, hence a single return value.\n function estimatedMintedShares(uint256 amount, bool isBackingToken) external view returns (uint256);\n\n /// Gets the estimated amount of YieldBearingTokens or BackingTokens received when calling `redeemXXX()` functions\n /// @param principals Amount of Principals (TPS) in PrincipalShare decimal precision\n /// @param yields Amount of Yields (TYS) in YieldShare decimal precision\n /// @param toBackingToken If true, redeem amount is estimated in BackingTokens instead of YieldBearingTokens\n /// @return Amount of YieldBearingTokens or BackingTokens in YBT/BT decimal precision\n function estimatedRedeem(\n uint256 principals,\n uint256 yields,\n bool toBackingToken\n ) external view returns (uint256);\n\n /// @dev This returns the stored Interest Rate of the YBT (Yield Bearing Token) pool\n /// it is safe to call this after updateInterestRate() was called\n /// @return Stored Interest Rate, decimal precision depends on specific TempusPool implementation\n function currentInterestRate() external view returns (uint256);\n\n /// @return Initial interest rate of the underlying pool,\n /// decimal precision depends on specific TempusPool implementation\n function initialInterestRate() external view returns (uint256);\n\n /// @return Interest rate at maturity of the underlying pool (or 0 if maturity not reached yet)\n /// decimal precision depends on specific TempusPool implementation\n function maturityInterestRate() external view returns (uint256);\n\n /// @return Rate of one Tempus Yield Share expressed in Asset Tokens\n function pricePerYieldShare() external returns (uint256);\n\n /// @return Rate of one Tempus Principal Share expressed in Asset Tokens\n function pricePerPrincipalShare() external returns (uint256);\n\n /// Calculated with stored interest rates\n /// @return Rate of one Tempus Yield Share expressed in Asset Tokens,\n function pricePerYieldShareStored() external view returns (uint256);\n\n /// Calculated with stored interest rates\n /// @return Rate of one Tempus Principal Share expressed in Asset Tokens\n function pricePerPrincipalShareStored() external view returns (uint256);\n\n /// @dev This returns actual Backing Token amount for amount of YBT (Yield Bearing Tokens)\n /// For example, in case of Aave and Lido the result is 1:1,\n /// and for compound is `yieldTokens * currentInterestRate`\n /// @param yieldTokens Amount of YBT in YBT decimal precision\n /// @param interestRate The current interest rate\n /// @return Amount of Backing Tokens for specified @param yieldTokens\n function numAssetsPerYieldToken(uint yieldTokens, uint interestRate) external view returns (uint);\n\n /// @dev This returns amount of YBT (Yield Bearing Tokens) that can be converted\n /// from @param backingTokens Backing Tokens\n /// @param backingTokens Amount of Backing Tokens in BT decimal precision\n /// @param interestRate The current interest rate\n /// @return Amount of YBT for specified @param backingTokens\n function numYieldTokensPerAsset(uint backingTokens, uint interestRate) external view returns (uint);\n}\n"
- },
- "contracts/token/IPoolShare.sol": {
- "content": "// SPDX-License-Identifier: BUSL-1.1\npragma solidity >=0.7.6 <0.9.0;\n\nimport \"../ITempusPool.sol\";\n\n/// Interface of Tokens representing the principal or yield shares of a pool.\ninterface IPoolShare {\n enum ShareKind {\n Principal,\n Yield\n }\n\n /// @return The kind of the share.\n function kind() external view returns (ShareKind);\n\n /// @return The pool this share is part of.\n function pool() external view returns (ITempusPool);\n\n /// @dev Price per single share expressed in Backing Tokens of the underlying pool.\n /// This is for the purpose of TempusAMM api support.\n /// Example: exchanging Tempus Yield Share to DAI\n /// @return 1e18 decimal conversion rate per share\n function getPricePerFullShare() external returns (uint256);\n\n /// @return 1e18 decimal stored conversion rate per share\n function getPricePerFullShareStored() external view returns (uint256);\n}\n"
- },
- "contracts/amm/TempusAMMUserDataHelpers.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity 0.7.6;\n\nimport \"./TempusAMM.sol\";\n\nlibrary TempusAMMUserDataHelpers {\n function joinKind(bytes memory self) internal pure returns (TempusAMM.JoinKind) {\n return abi.decode(self, (TempusAMM.JoinKind));\n }\n\n function exitKind(bytes memory self) internal pure returns (TempusAMM.ExitKind) {\n return abi.decode(self, (TempusAMM.ExitKind));\n }\n\n // Joins\n\n function initialAmountsIn(bytes memory self) internal pure returns (uint256[] memory amountsIn) {\n (, amountsIn) = abi.decode(self, (TempusAMM.JoinKind, uint256[]));\n }\n\n function exactTokensInForBptOut(bytes memory self)\n internal\n pure\n returns (uint256[] memory amountsIn, uint256 minBPTAmountOut)\n {\n (, amountsIn, minBPTAmountOut) = abi.decode(self, (TempusAMM.JoinKind, uint256[], uint256));\n }\n\n function tokenInForExactBptOut(bytes memory self) internal pure returns (uint256 bptAmountOut, uint256 tokenIndex) {\n (, bptAmountOut, tokenIndex) = abi.decode(self, (TempusAMM.JoinKind, uint256, uint256));\n }\n\n // Exits\n\n function exactBptInForTokenOut(bytes memory self) internal pure returns (uint256 bptAmountIn, uint256 tokenIndex) {\n (, bptAmountIn, tokenIndex) = abi.decode(self, (TempusAMM.ExitKind, uint256, uint256));\n }\n\n function exactBptInForTokensOut(bytes memory self) internal pure returns (uint256 bptAmountIn) {\n (, bptAmountIn) = abi.decode(self, (TempusAMM.ExitKind, uint256));\n }\n\n function bptInForExactTokensOut(bytes memory self)\n internal\n pure\n returns (uint256[] memory amountsOut, uint256 maxBPTAmountIn)\n {\n (, amountsOut, maxBPTAmountIn) = abi.decode(self, (TempusAMM.ExitKind, uint256[], uint256));\n }\n}\n"
- },
- "contracts/amm/VecMath.sol": {
- "content": "// SPDX-License-Identifier: MIT\npragma solidity 0.7.6;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol\";\n\n/// @dev helper library that does vector math\nlibrary VecMath {\n using FixedPoint for uint256;\n\n /// @dev Subtracting two vectors\n /// @notice Vectors must be of same length\n /// @param vec1 First vector, also result will be stored here\n /// @param vec2 Second vector\n function sub(uint256[] memory vec1, uint256[] memory vec2) internal pure {\n assert(vec1.length == vec2.length);\n for (uint256 i = 0; i < vec1.length; ++i) {\n vec1[i] = vec1[i].sub(vec2[i]);\n }\n }\n\n /// @dev Adding two vectors\n /// @notice Vectors must be of same length\n /// @param vec1 First vector, also result will be stored here\n /// @param vec2 Second vector\n function add(uint256[] memory vec1, uint256[] memory vec2) internal pure {\n assert(vec1.length == vec2.length);\n for (uint256 i = 0; i < vec1.length; ++i) {\n vec1[i] = vec1[i].add(vec2[i]);\n }\n }\n\n /// @dev Dot product of two vectors which is resulting in components, not final value\n /// @notice vec1[i] = vec1[i] * vec2[i]\n /// @notice Vectors must be of same length\n /// @param vec1 First vector, also result will be stored here\n /// @param vec2 Second vector\n function mul(\n uint256[] memory vec1,\n uint256[] memory vec2,\n uint256 one\n ) internal pure {\n assert(vec1.length == vec2.length);\n for (uint256 i = 0; i < vec1.length; ++i) {\n vec1[i] = (vec1[i] * vec2[i]) / one;\n }\n }\n\n /// @dev Dividing components of vec1 by components of vec2\n /// @notice vec1[i] = vec1[i] / vec2[i]\n /// @notice Vectors must be of same length\n /// @param vec1 First vector, also result will be stored here\n /// @param vec2 Second vector\n function div(\n uint256[] memory vec1,\n uint256[] memory vec2,\n uint256 one\n ) internal pure {\n assert(vec1.length == vec2.length);\n for (uint256 i = 0; i < vec1.length; ++i) {\n vec1[i] = (vec1[i] * one) / vec2[i];\n }\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/math/LogExpMath.sol": {
- "content": "// SPDX-License-Identifier: MIT\n// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated\n// documentation files (the “Software”), to deal in the Software without restriction, including without limitation the\n// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to\n// permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\n// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the\n// Software.\n\n// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE\n// WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\n// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\npragma solidity ^0.7.0;\n\nimport \"../helpers/BalancerErrors.sol\";\n\n/* solhint-disable */\n\n/**\n * @dev Exponentiation and logarithm functions for 18 decimal fixed point numbers (both base and exponent/argument).\n *\n * Exponentiation and logarithm with arbitrary bases (x^y and log_x(y)) are implemented by conversion to natural\n * exponentiation and logarithm (where the base is Euler's number).\n *\n * @author Fernando Martinelli - @fernandomartinelli\n * @author Sergio Yuhjtman - @sergioyuhjtman\n * @author Daniel Fernandez - @dmf7z\n */\nlibrary LogExpMath {\n // All fixed point multiplications and divisions are inlined. This means we need to divide by ONE when multiplying\n // two numbers, and multiply by ONE when dividing them.\n\n // All arguments and return values are 18 decimal fixed point numbers.\n int256 constant ONE_18 = 1e18;\n\n // Internally, intermediate values are computed with higher precision as 20 decimal fixed point numbers, and in the\n // case of ln36, 36 decimals.\n int256 constant ONE_20 = 1e20;\n int256 constant ONE_36 = 1e36;\n\n // The domain of natural exponentiation is bound by the word size and number of decimals used.\n //\n // Because internally the result will be stored using 20 decimals, the largest possible result is\n // (2^255 - 1) / 10^20, which makes the largest exponent ln((2^255 - 1) / 10^20) = 130.700829182905140221.\n // The smallest possible result is 10^(-18), which makes largest negative argument\n // ln(10^(-18)) = -41.446531673892822312.\n // We use 130.0 and -41.0 to have some safety margin.\n int256 constant MAX_NATURAL_EXPONENT = 130e18;\n int256 constant MIN_NATURAL_EXPONENT = -41e18;\n\n // Bounds for ln_36's argument. Both ln(0.9) and ln(1.1) can be represented with 36 decimal places in a fixed point\n // 256 bit integer.\n int256 constant LN_36_LOWER_BOUND = ONE_18 - 1e17;\n int256 constant LN_36_UPPER_BOUND = ONE_18 + 1e17;\n\n uint256 constant MILD_EXPONENT_BOUND = 2**254 / uint256(ONE_20);\n\n // 18 decimal constants\n int256 constant x0 = 128000000000000000000; // 2ˆ7\n int256 constant a0 = 38877084059945950922200000000000000000000000000000000000; // eˆ(x0) (no decimals)\n int256 constant x1 = 64000000000000000000; // 2ˆ6\n int256 constant a1 = 6235149080811616882910000000; // eˆ(x1) (no decimals)\n\n // 20 decimal constants\n int256 constant x2 = 3200000000000000000000; // 2ˆ5\n int256 constant a2 = 7896296018268069516100000000000000; // eˆ(x2)\n int256 constant x3 = 1600000000000000000000; // 2ˆ4\n int256 constant a3 = 888611052050787263676000000; // eˆ(x3)\n int256 constant x4 = 800000000000000000000; // 2ˆ3\n int256 constant a4 = 298095798704172827474000; // eˆ(x4)\n int256 constant x5 = 400000000000000000000; // 2ˆ2\n int256 constant a5 = 5459815003314423907810; // eˆ(x5)\n int256 constant x6 = 200000000000000000000; // 2ˆ1\n int256 constant a6 = 738905609893065022723; // eˆ(x6)\n int256 constant x7 = 100000000000000000000; // 2ˆ0\n int256 constant a7 = 271828182845904523536; // eˆ(x7)\n int256 constant x8 = 50000000000000000000; // 2ˆ-1\n int256 constant a8 = 164872127070012814685; // eˆ(x8)\n int256 constant x9 = 25000000000000000000; // 2ˆ-2\n int256 constant a9 = 128402541668774148407; // eˆ(x9)\n int256 constant x10 = 12500000000000000000; // 2ˆ-3\n int256 constant a10 = 113314845306682631683; // eˆ(x10)\n int256 constant x11 = 6250000000000000000; // 2ˆ-4\n int256 constant a11 = 106449445891785942956; // eˆ(x11)\n\n /**\n * @dev Exponentiation (x^y) with unsigned 18 decimal fixed point base and exponent.\n *\n * Reverts if ln(x) * y is smaller than `MIN_NATURAL_EXPONENT`, or larger than `MAX_NATURAL_EXPONENT`.\n */\n function pow(uint256 x, uint256 y) internal pure returns (uint256) {\n if (y == 0) {\n // We solve the 0^0 indetermination by making it equal one.\n return uint256(ONE_18);\n }\n\n if (x == 0) {\n return 0;\n }\n\n // Instead of computing x^y directly, we instead rely on the properties of logarithms and exponentiation to\n // arrive at that result. In particular, exp(ln(x)) = x, and ln(x^y) = y * ln(x). This means\n // x^y = exp(y * ln(x)).\n\n // The ln function takes a signed value, so we need to make sure x fits in the signed 256 bit range.\n _require(x < 2**255, Errors.X_OUT_OF_BOUNDS);\n int256 x_int256 = int256(x);\n\n // We will compute y * ln(x) in a single step. Depending on the value of x, we can either use ln or ln_36. In\n // both cases, we leave the division by ONE_18 (due to fixed point multiplication) to the end.\n\n // This prevents y * ln(x) from overflowing, and at the same time guarantees y fits in the signed 256 bit range.\n _require(y < MILD_EXPONENT_BOUND, Errors.Y_OUT_OF_BOUNDS);\n int256 y_int256 = int256(y);\n\n int256 logx_times_y;\n if (LN_36_LOWER_BOUND < x_int256 && x_int256 < LN_36_UPPER_BOUND) {\n int256 ln_36_x = _ln_36(x_int256);\n\n // ln_36_x has 36 decimal places, so multiplying by y_int256 isn't as straightforward, since we can't just\n // bring y_int256 to 36 decimal places, as it might overflow. Instead, we perform two 18 decimal\n // multiplications and add the results: one with the first 18 decimals of ln_36_x, and one with the\n // (downscaled) last 18 decimals.\n logx_times_y = ((ln_36_x / ONE_18) * y_int256 + ((ln_36_x % ONE_18) * y_int256) / ONE_18);\n } else {\n logx_times_y = _ln(x_int256) * y_int256;\n }\n logx_times_y /= ONE_18;\n\n // Finally, we compute exp(y * ln(x)) to arrive at x^y\n _require(\n MIN_NATURAL_EXPONENT <= logx_times_y && logx_times_y <= MAX_NATURAL_EXPONENT,\n Errors.PRODUCT_OUT_OF_BOUNDS\n );\n\n return uint256(exp(logx_times_y));\n }\n\n /**\n * @dev Natural exponentiation (e^x) with signed 18 decimal fixed point exponent.\n *\n * Reverts if `x` is smaller than MIN_NATURAL_EXPONENT, or larger than `MAX_NATURAL_EXPONENT`.\n */\n function exp(int256 x) internal pure returns (int256) {\n _require(x >= MIN_NATURAL_EXPONENT && x <= MAX_NATURAL_EXPONENT, Errors.INVALID_EXPONENT);\n\n if (x < 0) {\n // We only handle positive exponents: e^(-x) is computed as 1 / e^x. We can safely make x positive since it\n // fits in the signed 256 bit range (as it is larger than MIN_NATURAL_EXPONENT).\n // Fixed point division requires multiplying by ONE_18.\n return ((ONE_18 * ONE_18) / exp(-x));\n }\n\n // First, we use the fact that e^(x+y) = e^x * e^y to decompose x into a sum of powers of two, which we call x_n,\n // where x_n == 2^(7 - n), and e^x_n = a_n has been precomputed. We choose the first x_n, x0, to equal 2^7\n // because all larger powers are larger than MAX_NATURAL_EXPONENT, and therefore not present in the\n // decomposition.\n // At the end of this process we will have the product of all e^x_n = a_n that apply, and the remainder of this\n // decomposition, which will be lower than the smallest x_n.\n // exp(x) = k_0 * a_0 * k_1 * a_1 * ... + k_n * a_n * exp(remainder), where each k_n equals either 0 or 1.\n // We mutate x by subtracting x_n, making it the remainder of the decomposition.\n\n // The first two a_n (e^(2^7) and e^(2^6)) are too large if stored as 18 decimal numbers, and could cause\n // intermediate overflows. Instead we store them as plain integers, with 0 decimals.\n // Additionally, x0 + x1 is larger than MAX_NATURAL_EXPONENT, which means they will not both be present in the\n // decomposition.\n\n // For each x_n, we test if that term is present in the decomposition (if x is larger than it), and if so deduct\n // it and compute the accumulated product.\n\n int256 firstAN;\n if (x >= x0) {\n x -= x0;\n firstAN = a0;\n } else if (x >= x1) {\n x -= x1;\n firstAN = a1;\n } else {\n firstAN = 1; // One with no decimal places\n }\n\n // We now transform x into a 20 decimal fixed point number, to have enhanced precision when computing the\n // smaller terms.\n x *= 100;\n\n // `product` is the accumulated product of all a_n (except a0 and a1), which starts at 20 decimal fixed point\n // one. Recall that fixed point multiplication requires dividing by ONE_20.\n int256 product = ONE_20;\n\n if (x >= x2) {\n x -= x2;\n product = (product * a2) / ONE_20;\n }\n if (x >= x3) {\n x -= x3;\n product = (product * a3) / ONE_20;\n }\n if (x >= x4) {\n x -= x4;\n product = (product * a4) / ONE_20;\n }\n if (x >= x5) {\n x -= x5;\n product = (product * a5) / ONE_20;\n }\n if (x >= x6) {\n x -= x6;\n product = (product * a6) / ONE_20;\n }\n if (x >= x7) {\n x -= x7;\n product = (product * a7) / ONE_20;\n }\n if (x >= x8) {\n x -= x8;\n product = (product * a8) / ONE_20;\n }\n if (x >= x9) {\n x -= x9;\n product = (product * a9) / ONE_20;\n }\n\n // x10 and x11 are unnecessary here since we have high enough precision already.\n\n // Now we need to compute e^x, where x is small (in particular, it is smaller than x9). We use the Taylor series\n // expansion for e^x: 1 + x + (x^2 / 2!) + (x^3 / 3!) + ... + (x^n / n!).\n\n int256 seriesSum = ONE_20; // The initial one in the sum, with 20 decimal places.\n int256 term; // Each term in the sum, where the nth term is (x^n / n!).\n\n // The first term is simply x.\n term = x;\n seriesSum += term;\n\n // Each term (x^n / n!) equals the previous one times x, divided by n. Since x is a fixed point number,\n // multiplying by it requires dividing by ONE_20, but dividing by the non-fixed point n values does not.\n\n term = ((term * x) / ONE_20) / 2;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 3;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 4;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 5;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 6;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 7;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 8;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 9;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 10;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 11;\n seriesSum += term;\n\n term = ((term * x) / ONE_20) / 12;\n seriesSum += term;\n\n // 12 Taylor terms are sufficient for 18 decimal precision.\n\n // We now have the first a_n (with no decimals), and the product of all other a_n present, and the Taylor\n // approximation of the exponentiation of the remainder (both with 20 decimals). All that remains is to multiply\n // all three (one 20 decimal fixed point multiplication, dividing by ONE_20, and one integer multiplication),\n // and then drop two digits to return an 18 decimal value.\n\n return (((product * seriesSum) / ONE_20) * firstAN) / 100;\n }\n\n /**\n * @dev Logarithm (log(arg, base), with signed 18 decimal fixed point base and argument.\n */\n function log(int256 arg, int256 base) internal pure returns (int256) {\n // This performs a simple base change: log(arg, base) = ln(arg) / ln(base).\n\n // Both logBase and logArg are computed as 36 decimal fixed point numbers, either by using ln_36, or by\n // upscaling.\n\n int256 logBase;\n if (LN_36_LOWER_BOUND < base && base < LN_36_UPPER_BOUND) {\n logBase = _ln_36(base);\n } else {\n logBase = _ln(base) * ONE_18;\n }\n\n int256 logArg;\n if (LN_36_LOWER_BOUND < arg && arg < LN_36_UPPER_BOUND) {\n logArg = _ln_36(arg);\n } else {\n logArg = _ln(arg) * ONE_18;\n }\n\n // When dividing, we multiply by ONE_18 to arrive at a result with 18 decimal places\n return (logArg * ONE_18) / logBase;\n }\n\n /**\n * @dev Natural logarithm (ln(a)) with signed 18 decimal fixed point argument.\n */\n function ln(int256 a) internal pure returns (int256) {\n // The real natural logarithm is not defined for negative numbers or zero.\n _require(a > 0, Errors.OUT_OF_BOUNDS);\n if (LN_36_LOWER_BOUND < a && a < LN_36_UPPER_BOUND) {\n return _ln_36(a) / ONE_18;\n } else {\n return _ln(a);\n }\n }\n\n /**\n * @dev Internal natural logarithm (ln(a)) with signed 18 decimal fixed point argument.\n */\n function _ln(int256 a) private pure returns (int256) {\n if (a < ONE_18) {\n // Since ln(a^k) = k * ln(a), we can compute ln(a) as ln(a) = ln((1/a)^(-1)) = - ln((1/a)). If a is less\n // than one, 1/a will be greater than one, and this if statement will not be entered in the recursive call.\n // Fixed point division requires multiplying by ONE_18.\n return (-_ln((ONE_18 * ONE_18) / a));\n }\n\n // First, we use the fact that ln^(a * b) = ln(a) + ln(b) to decompose ln(a) into a sum of powers of two, which\n // we call x_n, where x_n == 2^(7 - n), which are the natural logarithm of precomputed quantities a_n (that is,\n // ln(a_n) = x_n). We choose the first x_n, x0, to equal 2^7 because the exponential of all larger powers cannot\n // be represented as 18 fixed point decimal numbers in 256 bits, and are therefore larger than a.\n // At the end of this process we will have the sum of all x_n = ln(a_n) that apply, and the remainder of this\n // decomposition, which will be lower than the smallest a_n.\n // ln(a) = k_0 * x_0 + k_1 * x_1 + ... + k_n * x_n + ln(remainder), where each k_n equals either 0 or 1.\n // We mutate a by subtracting a_n, making it the remainder of the decomposition.\n\n // For reasons related to how `exp` works, the first two a_n (e^(2^7) and e^(2^6)) are not stored as fixed point\n // numbers with 18 decimals, but instead as plain integers with 0 decimals, so we need to multiply them by\n // ONE_18 to convert them to fixed point.\n // For each a_n, we test if that term is present in the decomposition (if a is larger than it), and if so divide\n // by it and compute the accumulated sum.\n\n int256 sum = 0;\n if (a >= a0 * ONE_18) {\n a /= a0; // Integer, not fixed point division\n sum += x0;\n }\n\n if (a >= a1 * ONE_18) {\n a /= a1; // Integer, not fixed point division\n sum += x1;\n }\n\n // All other a_n and x_n are stored as 20 digit fixed point numbers, so we convert the sum and a to this format.\n sum *= 100;\n a *= 100;\n\n // Because further a_n are 20 digit fixed point numbers, we multiply by ONE_20 when dividing by them.\n\n if (a >= a2) {\n a = (a * ONE_20) / a2;\n sum += x2;\n }\n\n if (a >= a3) {\n a = (a * ONE_20) / a3;\n sum += x3;\n }\n\n if (a >= a4) {\n a = (a * ONE_20) / a4;\n sum += x4;\n }\n\n if (a >= a5) {\n a = (a * ONE_20) / a5;\n sum += x5;\n }\n\n if (a >= a6) {\n a = (a * ONE_20) / a6;\n sum += x6;\n }\n\n if (a >= a7) {\n a = (a * ONE_20) / a7;\n sum += x7;\n }\n\n if (a >= a8) {\n a = (a * ONE_20) / a8;\n sum += x8;\n }\n\n if (a >= a9) {\n a = (a * ONE_20) / a9;\n sum += x9;\n }\n\n if (a >= a10) {\n a = (a * ONE_20) / a10;\n sum += x10;\n }\n\n if (a >= a11) {\n a = (a * ONE_20) / a11;\n sum += x11;\n }\n\n // a is now a small number (smaller than a_11, which roughly equals 1.06). This means we can use a Taylor series\n // that converges rapidly for values of `a` close to one - the same one used in ln_36.\n // Let z = (a - 1) / (a + 1).\n // ln(a) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))\n\n // Recall that 20 digit fixed point division requires multiplying by ONE_20, and multiplication requires\n // division by ONE_20.\n int256 z = ((a - ONE_20) * ONE_20) / (a + ONE_20);\n int256 z_squared = (z * z) / ONE_20;\n\n // num is the numerator of the series: the z^(2 * n + 1) term\n int256 num = z;\n\n // seriesSum holds the accumulated sum of each term in the series, starting with the initial z\n int256 seriesSum = num;\n\n // In each step, the numerator is multiplied by z^2\n num = (num * z_squared) / ONE_20;\n seriesSum += num / 3;\n\n num = (num * z_squared) / ONE_20;\n seriesSum += num / 5;\n\n num = (num * z_squared) / ONE_20;\n seriesSum += num / 7;\n\n num = (num * z_squared) / ONE_20;\n seriesSum += num / 9;\n\n num = (num * z_squared) / ONE_20;\n seriesSum += num / 11;\n\n // 6 Taylor terms are sufficient for 36 decimal precision.\n\n // Finally, we multiply by 2 (non fixed point) to compute ln(remainder)\n seriesSum *= 2;\n\n // We now have the sum of all x_n present, and the Taylor approximation of the logarithm of the remainder (both\n // with 20 decimals). All that remains is to sum these two, and then drop two digits to return a 18 decimal\n // value.\n\n return (sum + seriesSum) / 100;\n }\n\n /**\n * @dev Intrnal high precision (36 decimal places) natural logarithm (ln(x)) with signed 18 decimal fixed point argument,\n * for x close to one.\n *\n * Should only be used if x is between LN_36_LOWER_BOUND and LN_36_UPPER_BOUND.\n */\n function _ln_36(int256 x) private pure returns (int256) {\n // Since ln(1) = 0, a value of x close to one will yield a very small result, which makes using 36 digits\n // worthwhile.\n\n // First, we transform x to a 36 digit fixed point value.\n x *= ONE_18;\n\n // We will use the following Taylor expansion, which converges very rapidly. Let z = (x - 1) / (x + 1).\n // ln(x) = 2 * (z + z^3 / 3 + z^5 / 5 + z^7 / 7 + ... + z^(2 * n + 1) / (2 * n + 1))\n\n // Recall that 36 digit fixed point division requires multiplying by ONE_36, and multiplication requires\n // division by ONE_36.\n int256 z = ((x - ONE_36) * ONE_36) / (x + ONE_36);\n int256 z_squared = (z * z) / ONE_36;\n\n // num is the numerator of the series: the z^(2 * n + 1) term\n int256 num = z;\n\n // seriesSum holds the accumulated sum of each term in the series, starting with the initial z\n int256 seriesSum = num;\n\n // In each step, the numerator is multiplied by z^2\n num = (num * z_squared) / ONE_36;\n seriesSum += num / 3;\n\n num = (num * z_squared) / ONE_36;\n seriesSum += num / 5;\n\n num = (num * z_squared) / ONE_36;\n seriesSum += num / 7;\n\n num = (num * z_squared) / ONE_36;\n seriesSum += num / 9;\n\n num = (num * z_squared) / ONE_36;\n seriesSum += num / 11;\n\n num = (num * z_squared) / ONE_36;\n seriesSum += num / 13;\n\n num = (num * z_squared) / ONE_36;\n seriesSum += num / 15;\n\n // 8 Taylor terms are sufficient for 36 decimal precision.\n\n // All that remains is multiplying by 2 (non fixed point).\n return seriesSum * 2;\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/BalancerErrors.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\n// solhint-disable\n\n/**\n * @dev Reverts if `condition` is false, with a revert reason containing `errorCode`. Only codes up to 999 are\n * supported.\n */\nfunction _require(bool condition, uint256 errorCode) pure {\n if (!condition) _revert(errorCode);\n}\n\n/**\n * @dev Reverts with a revert reason containing `errorCode`. Only codes up to 999 are supported.\n */\nfunction _revert(uint256 errorCode) pure {\n // We're going to dynamically create a revert string based on the error code, with the following format:\n // 'BAL#{errorCode}'\n // where the code is left-padded with zeroes to three digits (so they range from 000 to 999).\n //\n // We don't have revert strings embedded in the contract to save bytecode size: it takes much less space to store a\n // number (8 to 16 bits) than the individual string characters.\n //\n // The dynamic string creation algorithm that follows could be implemented in Solidity, but assembly allows for a\n // much denser implementation, again saving bytecode size. Given this function unconditionally reverts, this is a\n // safe place to rely on it without worrying about how its usage might affect e.g. memory contents.\n assembly {\n // First, we need to compute the ASCII representation of the error code. We assume that it is in the 0-999\n // range, so we only need to convert three digits. To convert the digits to ASCII, we add 0x30, the value for\n // the '0' character.\n\n let units := add(mod(errorCode, 10), 0x30)\n\n errorCode := div(errorCode, 10)\n let tenths := add(mod(errorCode, 10), 0x30)\n\n errorCode := div(errorCode, 10)\n let hundreds := add(mod(errorCode, 10), 0x30)\n\n // With the individual characters, we can now construct the full string. The \"BAL#\" part is a known constant\n // (0x42414c23): we simply shift this by 24 (to provide space for the 3 bytes of the error code), and add the\n // characters to it, each shifted by a multiple of 8.\n // The revert reason is then shifted left by 200 bits (256 minus the length of the string, 7 characters * 8 bits\n // per character = 56) to locate it in the most significant part of the 256 slot (the beginning of a byte\n // array).\n\n let revertReason := shl(200, add(0x42414c23000000, add(add(units, shl(8, tenths)), shl(16, hundreds))))\n\n // We can now encode the reason in memory, which can be safely overwritten as we're about to revert. The encoded\n // message will have the following layout:\n // [ revert reason identifier ] [ string location offset ] [ string length ] [ string contents ]\n\n // The Solidity revert reason identifier is 0x08c739a0, the function selector of the Error(string) function. We\n // also write zeroes to the next 28 bytes of memory, but those are about to be overwritten.\n mstore(0x0, 0x08c379a000000000000000000000000000000000000000000000000000000000)\n // Next is the offset to the location of the string, which will be placed immediately after (20 bytes away).\n mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)\n // The string length is fixed: 7 characters.\n mstore(0x24, 7)\n // Finally, the string itself is stored.\n mstore(0x44, revertReason)\n\n // Even if the string is only 7 bytes long, we need to return a full 32 byte slot containing it. The length of\n // the encoded message is therefore 4 + 32 + 32 + 32 = 100.\n revert(0, 100)\n }\n}\n\nlibrary Errors {\n // Math\n uint256 internal constant ADD_OVERFLOW = 0;\n uint256 internal constant SUB_OVERFLOW = 1;\n uint256 internal constant SUB_UNDERFLOW = 2;\n uint256 internal constant MUL_OVERFLOW = 3;\n uint256 internal constant ZERO_DIVISION = 4;\n uint256 internal constant DIV_INTERNAL = 5;\n uint256 internal constant X_OUT_OF_BOUNDS = 6;\n uint256 internal constant Y_OUT_OF_BOUNDS = 7;\n uint256 internal constant PRODUCT_OUT_OF_BOUNDS = 8;\n uint256 internal constant INVALID_EXPONENT = 9;\n\n // Input\n uint256 internal constant OUT_OF_BOUNDS = 100;\n uint256 internal constant UNSORTED_ARRAY = 101;\n uint256 internal constant UNSORTED_TOKENS = 102;\n uint256 internal constant INPUT_LENGTH_MISMATCH = 103;\n uint256 internal constant ZERO_TOKEN = 104;\n\n // Shared pools\n uint256 internal constant MIN_TOKENS = 200;\n uint256 internal constant MAX_TOKENS = 201;\n uint256 internal constant MAX_SWAP_FEE_PERCENTAGE = 202;\n uint256 internal constant MIN_SWAP_FEE_PERCENTAGE = 203;\n uint256 internal constant MINIMUM_BPT = 204;\n uint256 internal constant CALLER_NOT_VAULT = 205;\n uint256 internal constant UNINITIALIZED = 206;\n uint256 internal constant BPT_IN_MAX_AMOUNT = 207;\n uint256 internal constant BPT_OUT_MIN_AMOUNT = 208;\n uint256 internal constant EXPIRED_PERMIT = 209;\n uint256 internal constant NOT_TWO_TOKENS = 210;\n\n // Pools\n uint256 internal constant MIN_AMP = 300;\n uint256 internal constant MAX_AMP = 301;\n uint256 internal constant MIN_WEIGHT = 302;\n uint256 internal constant MAX_STABLE_TOKENS = 303;\n uint256 internal constant MAX_IN_RATIO = 304;\n uint256 internal constant MAX_OUT_RATIO = 305;\n uint256 internal constant MIN_BPT_IN_FOR_TOKEN_OUT = 306;\n uint256 internal constant MAX_OUT_BPT_FOR_TOKEN_IN = 307;\n uint256 internal constant NORMALIZED_WEIGHT_INVARIANT = 308;\n uint256 internal constant INVALID_TOKEN = 309;\n uint256 internal constant UNHANDLED_JOIN_KIND = 310;\n uint256 internal constant ZERO_INVARIANT = 311;\n uint256 internal constant ORACLE_INVALID_SECONDS_QUERY = 312;\n uint256 internal constant ORACLE_NOT_INITIALIZED = 313;\n uint256 internal constant ORACLE_QUERY_TOO_OLD = 314;\n uint256 internal constant ORACLE_INVALID_INDEX = 315;\n uint256 internal constant ORACLE_BAD_SECS = 316;\n uint256 internal constant AMP_END_TIME_TOO_CLOSE = 317;\n uint256 internal constant AMP_ONGOING_UPDATE = 318;\n uint256 internal constant AMP_RATE_TOO_HIGH = 319;\n uint256 internal constant AMP_NO_ONGOING_UPDATE = 320;\n uint256 internal constant STABLE_INVARIANT_DIDNT_CONVERGE = 321;\n uint256 internal constant STABLE_GET_BALANCE_DIDNT_CONVERGE = 322;\n uint256 internal constant RELAYER_NOT_CONTRACT = 323;\n uint256 internal constant BASE_POOL_RELAYER_NOT_CALLED = 324;\n uint256 internal constant REBALANCING_RELAYER_REENTERED = 325;\n uint256 internal constant GRADUAL_UPDATE_TIME_TRAVEL = 326;\n uint256 internal constant SWAPS_DISABLED = 327;\n uint256 internal constant CALLER_IS_NOT_LBP_OWNER = 328;\n uint256 internal constant PRICE_RATE_OVERFLOW = 329;\n\n // Lib\n uint256 internal constant REENTRANCY = 400;\n uint256 internal constant SENDER_NOT_ALLOWED = 401;\n uint256 internal constant PAUSED = 402;\n uint256 internal constant PAUSE_WINDOW_EXPIRED = 403;\n uint256 internal constant MAX_PAUSE_WINDOW_DURATION = 404;\n uint256 internal constant MAX_BUFFER_PERIOD_DURATION = 405;\n uint256 internal constant INSUFFICIENT_BALANCE = 406;\n uint256 internal constant INSUFFICIENT_ALLOWANCE = 407;\n uint256 internal constant ERC20_TRANSFER_FROM_ZERO_ADDRESS = 408;\n uint256 internal constant ERC20_TRANSFER_TO_ZERO_ADDRESS = 409;\n uint256 internal constant ERC20_MINT_TO_ZERO_ADDRESS = 410;\n uint256 internal constant ERC20_BURN_FROM_ZERO_ADDRESS = 411;\n uint256 internal constant ERC20_APPROVE_FROM_ZERO_ADDRESS = 412;\n uint256 internal constant ERC20_APPROVE_TO_ZERO_ADDRESS = 413;\n uint256 internal constant ERC20_TRANSFER_EXCEEDS_ALLOWANCE = 414;\n uint256 internal constant ERC20_DECREASED_ALLOWANCE_BELOW_ZERO = 415;\n uint256 internal constant ERC20_TRANSFER_EXCEEDS_BALANCE = 416;\n uint256 internal constant ERC20_BURN_EXCEEDS_ALLOWANCE = 417;\n uint256 internal constant SAFE_ERC20_CALL_FAILED = 418;\n uint256 internal constant ADDRESS_INSUFFICIENT_BALANCE = 419;\n uint256 internal constant ADDRESS_CANNOT_SEND_VALUE = 420;\n uint256 internal constant SAFE_CAST_VALUE_CANT_FIT_INT256 = 421;\n uint256 internal constant GRANT_SENDER_NOT_ADMIN = 422;\n uint256 internal constant REVOKE_SENDER_NOT_ADMIN = 423;\n uint256 internal constant RENOUNCE_SENDER_NOT_ALLOWED = 424;\n uint256 internal constant BUFFER_PERIOD_EXPIRED = 425;\n uint256 internal constant CALLER_IS_NOT_OWNER = 426;\n uint256 internal constant NEW_OWNER_IS_ZERO = 427;\n uint256 internal constant CODE_DEPLOYMENT_FAILED = 428;\n\n // Vault\n uint256 internal constant INVALID_POOL_ID = 500;\n uint256 internal constant CALLER_NOT_POOL = 501;\n uint256 internal constant SENDER_NOT_ASSET_MANAGER = 502;\n uint256 internal constant USER_DOESNT_ALLOW_RELAYER = 503;\n uint256 internal constant INVALID_SIGNATURE = 504;\n uint256 internal constant EXIT_BELOW_MIN = 505;\n uint256 internal constant JOIN_ABOVE_MAX = 506;\n uint256 internal constant SWAP_LIMIT = 507;\n uint256 internal constant SWAP_DEADLINE = 508;\n uint256 internal constant CANNOT_SWAP_SAME_TOKEN = 509;\n uint256 internal constant UNKNOWN_AMOUNT_IN_FIRST_SWAP = 510;\n uint256 internal constant MALCONSTRUCTED_MULTIHOP_SWAP = 511;\n uint256 internal constant INTERNAL_BALANCE_OVERFLOW = 512;\n uint256 internal constant INSUFFICIENT_INTERNAL_BALANCE = 513;\n uint256 internal constant INVALID_ETH_INTERNAL_BALANCE = 514;\n uint256 internal constant INVALID_POST_LOAN_BALANCE = 515;\n uint256 internal constant INSUFFICIENT_ETH = 516;\n uint256 internal constant UNALLOCATED_ETH = 517;\n uint256 internal constant ETH_TRANSFER = 518;\n uint256 internal constant CANNOT_USE_ETH_SENTINEL = 519;\n uint256 internal constant TOKENS_MISMATCH = 520;\n uint256 internal constant TOKEN_NOT_REGISTERED = 521;\n uint256 internal constant TOKEN_ALREADY_REGISTERED = 522;\n uint256 internal constant TOKENS_ALREADY_SET = 523;\n uint256 internal constant TOKENS_LENGTH_MUST_BE_2 = 524;\n uint256 internal constant NONZERO_TOKEN_BALANCE = 525;\n uint256 internal constant BALANCE_TOTAL_OVERFLOW = 526;\n uint256 internal constant POOL_NO_TOKENS = 527;\n uint256 internal constant INSUFFICIENT_FLASH_LOAN_BALANCE = 528;\n\n // Fees\n uint256 internal constant SWAP_FEE_PERCENTAGE_TOO_HIGH = 600;\n uint256 internal constant FLASH_LOAN_FEE_PERCENTAGE_TOO_HIGH = 601;\n uint256 internal constant INSUFFICIENT_FLASH_LOAN_FEE_AMOUNT = 602;\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/IERC20.sol": {
- "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n /**\n * @dev Returns the amount of tokens in existence.\n */\n function totalSupply() external view returns (uint256);\n\n /**\n * @dev Returns the amount of tokens owned by `account`.\n */\n function balanceOf(address account) external view returns (uint256);\n\n /**\n * @dev Moves `amount` tokens from the caller's account to `recipient`.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transfer(address recipient, uint256 amount) external returns (bool);\n\n /**\n * @dev Returns the remaining number of tokens that `spender` will be\n * allowed to spend on behalf of `owner` through {transferFrom}. This is\n * zero by default.\n *\n * This value changes when {approve} or {transferFrom} are called.\n */\n function allowance(address owner, address spender) external view returns (uint256);\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * IMPORTANT: Beware that changing an allowance with this method brings the risk\n * that someone may use both the old and the new allowance by unfortunate\n * transaction ordering. One possible solution to mitigate this race\n * condition is to first reduce the spender's allowance to 0 and set the\n * desired value afterwards:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n *\n * Emits an {Approval} event.\n */\n function approve(address spender, uint256 amount) external returns (bool);\n\n /**\n * @dev Moves `amount` tokens from `sender` to `recipient` using the\n * allowance mechanism. `amount` is then deducted from the caller's\n * allowance.\n *\n * Returns a boolean value indicating whether the operation succeeded.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) external returns (bool);\n\n /**\n * @dev Emitted when `value` tokens are moved from one account (`from`) to\n * another (`to`).\n *\n * Note that `value` may be zero.\n */\n event Transfer(address indexed from, address indexed to, uint256 value);\n\n /**\n * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n * a call to {approve}. `value` is the new allowance.\n */\n event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"
- },
- "@balancer-labs/v2-pool-utils/contracts/BasePool.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/math/Math.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/math/FixedPoint.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/helpers/InputHelpers.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/helpers/TemporarilyPausable.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/helpers/WordCodec.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/ERC20.sol\";\n\nimport \"@balancer-labs/v2-vault/contracts/interfaces/IVault.sol\";\nimport \"@balancer-labs/v2-vault/contracts/interfaces/IBasePool.sol\";\n\nimport \"@balancer-labs/v2-asset-manager-utils/contracts/IAssetManager.sol\";\n\nimport \"./BalancerPoolToken.sol\";\nimport \"./BasePoolAuthorization.sol\";\n\n// solhint-disable max-states-count\n\n/**\n * @dev Reference implementation for the base layer of a Pool contract that manages a single Pool with optional\n * Asset Managers, an admin-controlled swap fee percentage, and an emergency pause mechanism.\n *\n * Note that neither swap fees nor the pause mechanism are used by this contract. They are passed through so that\n * derived contracts can use them via the `_addSwapFeeAmount` and `_subtractSwapFeeAmount` functions, and the\n * `whenNotPaused` modifier.\n *\n * No admin permissions are checked here: instead, this contract delegates that to the Vault's own Authorizer.\n *\n * Because this contract doesn't implement the swap hooks, derived contracts should generally inherit from\n * BaseGeneralPool or BaseMinimalSwapInfoPool. Otherwise, subclasses must inherit from the corresponding interfaces\n * and implement the swap callbacks themselves.\n */\nabstract contract BasePool is IBasePool, BasePoolAuthorization, BalancerPoolToken, TemporarilyPausable {\n using WordCodec for bytes32;\n using FixedPoint for uint256;\n\n uint256 private constant _MIN_TOKENS = 2;\n\n // 1e18 corresponds to 1.0, or a 100% fee\n uint256 private constant _MIN_SWAP_FEE_PERCENTAGE = 1e12; // 0.0001%\n uint256 private constant _MAX_SWAP_FEE_PERCENTAGE = 1e17; // 10%\n\n uint256 private constant _MINIMUM_BPT = 1e6;\n\n // Storage slot that can be used to store unrelated pieces of information. In particular, by default is used\n // to store only the swap fee percentage of a pool. But it can be extended to store some more pieces of information.\n // The swap fee percentage is stored in the most-significant 64 bits, therefore the remaining 192 bits can be\n // used to store any other piece of information.\n bytes32 private _miscData;\n uint256 private constant _SWAP_FEE_PERCENTAGE_OFFSET = 192;\n\n IVault private immutable _vault;\n bytes32 private immutable _poolId;\n\n event SwapFeePercentageChanged(uint256 swapFeePercentage);\n\n constructor(\n IVault vault,\n IVault.PoolSpecialization specialization,\n string memory name,\n string memory symbol,\n IERC20[] memory tokens,\n address[] memory assetManagers,\n uint256 swapFeePercentage,\n uint256 pauseWindowDuration,\n uint256 bufferPeriodDuration,\n address owner\n )\n // Base Pools are expected to be deployed using factories. By using the factory address as the action\n // disambiguator, we make all Pools deployed by the same factory share action identifiers. This allows for\n // simpler management of permissions (such as being able to manage granting the 'set fee percentage' action in\n // any Pool created by the same factory), while still making action identifiers unique among different factories\n // if the selectors match, preventing accidental errors.\n Authentication(bytes32(uint256(msg.sender)))\n BalancerPoolToken(name, symbol)\n BasePoolAuthorization(owner)\n TemporarilyPausable(pauseWindowDuration, bufferPeriodDuration)\n {\n _require(tokens.length >= _MIN_TOKENS, Errors.MIN_TOKENS);\n _require(tokens.length <= _getMaxTokens(), Errors.MAX_TOKENS);\n\n // The Vault only requires the token list to be ordered for the Two Token Pools specialization. However,\n // to make the developer experience consistent, we are requiring this condition for all the native pools.\n // Also, since these Pools will register tokens only once, we can ensure the Pool tokens will follow the same\n // order. We rely on this property to make Pools simpler to write, as it lets us assume that the\n // order of token-specific parameters (such as token weights) will not change.\n InputHelpers.ensureArrayIsSorted(tokens);\n\n _setSwapFeePercentage(swapFeePercentage);\n\n bytes32 poolId = vault.registerPool(specialization);\n\n vault.registerTokens(poolId, tokens, assetManagers);\n\n // Set immutable state variables - these cannot be read from during construction\n _vault = vault;\n _poolId = poolId;\n }\n\n // Getters / Setters\n\n function getVault() public view returns (IVault) {\n return _vault;\n }\n\n function getPoolId() public view override returns (bytes32) {\n return _poolId;\n }\n\n function _getTotalTokens() internal view virtual returns (uint256);\n\n function _getMaxTokens() internal pure virtual returns (uint256);\n\n function getSwapFeePercentage() public view returns (uint256) {\n return _miscData.decodeUint64(_SWAP_FEE_PERCENTAGE_OFFSET);\n }\n\n function setSwapFeePercentage(uint256 swapFeePercentage) external virtual authenticate whenNotPaused {\n _setSwapFeePercentage(swapFeePercentage);\n }\n\n function _setSwapFeePercentage(uint256 swapFeePercentage) private {\n _require(swapFeePercentage >= _MIN_SWAP_FEE_PERCENTAGE, Errors.MIN_SWAP_FEE_PERCENTAGE);\n _require(swapFeePercentage <= _MAX_SWAP_FEE_PERCENTAGE, Errors.MAX_SWAP_FEE_PERCENTAGE);\n\n _miscData = _miscData.insertUint64(swapFeePercentage, _SWAP_FEE_PERCENTAGE_OFFSET);\n emit SwapFeePercentageChanged(swapFeePercentage);\n }\n\n function setAssetManagerPoolConfig(IERC20 token, bytes memory poolConfig)\n public\n virtual\n authenticate\n whenNotPaused\n {\n _setAssetManagerPoolConfig(token, poolConfig);\n }\n\n function _setAssetManagerPoolConfig(IERC20 token, bytes memory poolConfig) private {\n bytes32 poolId = getPoolId();\n (, , , address assetManager) = getVault().getPoolTokenInfo(poolId, token);\n\n IAssetManager(assetManager).setConfig(poolId, poolConfig);\n }\n\n function setPaused(bool paused) external authenticate {\n _setPaused(paused);\n }\n\n function _isOwnerOnlyAction(bytes32 actionId) internal view virtual override returns (bool) {\n return\n (actionId == getActionId(this.setSwapFeePercentage.selector)) ||\n (actionId == getActionId(this.setAssetManagerPoolConfig.selector));\n }\n\n function _getMiscData() internal view returns (bytes32) {\n return _miscData;\n }\n\n /**\n * Inserts data into the least-significant 192 bits of the misc data storage slot.\n * Note that the remaining 64 bits are used for the swap fee percentage and cannot be overloaded.\n */\n function _setMiscData(bytes32 newData) internal {\n _miscData = _miscData.insertBits192(newData, 0);\n }\n\n // Join / Exit Hooks\n\n modifier onlyVault(bytes32 poolId) {\n _require(msg.sender == address(getVault()), Errors.CALLER_NOT_VAULT);\n _require(poolId == getPoolId(), Errors.INVALID_POOL_ID);\n _;\n }\n\n function onJoinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n bytes memory userData\n ) public virtual override onlyVault(poolId) returns (uint256[] memory, uint256[] memory) {\n uint256[] memory scalingFactors = _scalingFactors();\n\n if (totalSupply() == 0) {\n (uint256 bptAmountOut, uint256[] memory amountsIn) = _onInitializePool(\n poolId,\n sender,\n recipient,\n scalingFactors,\n userData\n );\n\n // On initialization, we lock _MINIMUM_BPT by minting it for the zero address. This BPT acts as a minimum\n // as it will never be burned, which reduces potential issues with rounding, and also prevents the Pool from\n // ever being fully drained.\n _require(bptAmountOut >= _MINIMUM_BPT, Errors.MINIMUM_BPT);\n _mintPoolTokens(address(0), _MINIMUM_BPT);\n _mintPoolTokens(recipient, bptAmountOut - _MINIMUM_BPT);\n\n // amountsIn are amounts entering the Pool, so we round up.\n _downscaleUpArray(amountsIn, scalingFactors);\n\n return (amountsIn, new uint256[](_getTotalTokens()));\n } else {\n _upscaleArray(balances, scalingFactors);\n (uint256 bptAmountOut, uint256[] memory amountsIn, uint256[] memory dueProtocolFeeAmounts) = _onJoinPool(\n poolId,\n sender,\n recipient,\n balances,\n lastChangeBlock,\n protocolSwapFeePercentage,\n scalingFactors,\n userData\n );\n\n // Note we no longer use `balances` after calling `_onJoinPool`, which may mutate it.\n\n _mintPoolTokens(recipient, bptAmountOut);\n\n // amountsIn are amounts entering the Pool, so we round up.\n _downscaleUpArray(amountsIn, scalingFactors);\n // dueProtocolFeeAmounts are amounts exiting the Pool, so we round down.\n _downscaleDownArray(dueProtocolFeeAmounts, scalingFactors);\n\n return (amountsIn, dueProtocolFeeAmounts);\n }\n }\n\n function onExitPool(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n bytes memory userData\n ) public virtual override onlyVault(poolId) returns (uint256[] memory, uint256[] memory) {\n uint256[] memory scalingFactors = _scalingFactors();\n _upscaleArray(balances, scalingFactors);\n\n (uint256 bptAmountIn, uint256[] memory amountsOut, uint256[] memory dueProtocolFeeAmounts) = _onExitPool(\n poolId,\n sender,\n recipient,\n balances,\n lastChangeBlock,\n protocolSwapFeePercentage,\n scalingFactors,\n userData\n );\n\n // Note we no longer use `balances` after calling `_onExitPool`, which may mutate it.\n\n _burnPoolTokens(sender, bptAmountIn);\n\n // Both amountsOut and dueProtocolFeeAmounts are amounts exiting the Pool, so we round down.\n _downscaleDownArray(amountsOut, scalingFactors);\n _downscaleDownArray(dueProtocolFeeAmounts, scalingFactors);\n\n return (amountsOut, dueProtocolFeeAmounts);\n }\n\n // Query functions\n\n /**\n * @dev Returns the amount of BPT that would be granted to `recipient` if the `onJoinPool` hook were called by the\n * Vault with the same arguments, along with the number of tokens `sender` would have to supply.\n *\n * This function is not meant to be called directly, but rather from a helper contract that fetches current Vault\n * data, such as the protocol swap fee percentage and Pool balances.\n *\n * Like `IVault.queryBatchSwap`, this function is not view due to internal implementation details: the caller must\n * explicitly use eth_call instead of eth_sendTransaction.\n */\n function queryJoin(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n bytes memory userData\n ) external returns (uint256 bptOut, uint256[] memory amountsIn) {\n InputHelpers.ensureInputLengthMatch(balances.length, _getTotalTokens());\n\n _queryAction(\n poolId,\n sender,\n recipient,\n balances,\n lastChangeBlock,\n protocolSwapFeePercentage,\n userData,\n _onJoinPool,\n _downscaleUpArray\n );\n\n // The `return` opcode is executed directly inside `_queryAction`, so execution never reaches this statement,\n // and we don't need to return anything here - it just silences compiler warnings.\n return (bptOut, amountsIn);\n }\n\n /**\n * @dev Returns the amount of BPT that would be burned from `sender` if the `onExitPool` hook were called by the\n * Vault with the same arguments, along with the number of tokens `recipient` would receive.\n *\n * This function is not meant to be called directly, but rather from a helper contract that fetches current Vault\n * data, such as the protocol swap fee percentage and Pool balances.\n *\n * Like `IVault.queryBatchSwap`, this function is not view due to internal implementation details: the caller must\n * explicitly use eth_call instead of eth_sendTransaction.\n */\n function queryExit(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n bytes memory userData\n ) external returns (uint256 bptIn, uint256[] memory amountsOut) {\n InputHelpers.ensureInputLengthMatch(balances.length, _getTotalTokens());\n\n _queryAction(\n poolId,\n sender,\n recipient,\n balances,\n lastChangeBlock,\n protocolSwapFeePercentage,\n userData,\n _onExitPool,\n _downscaleDownArray\n );\n\n // The `return` opcode is executed directly inside `_queryAction`, so execution never reaches this statement,\n // and we don't need to return anything here - it just silences compiler warnings.\n return (bptIn, amountsOut);\n }\n\n // Internal hooks to be overridden by derived contracts - all token amounts (except BPT) in these interfaces are\n // upscaled.\n\n /**\n * @dev Called when the Pool is joined for the first time; that is, when the BPT total supply is zero.\n *\n * Returns the amount of BPT to mint, and the token amounts the Pool will receive in return.\n *\n * Minted BPT will be sent to `recipient`, except for _MINIMUM_BPT, which will be deducted from this amount and sent\n * to the zero address instead. This will cause that BPT to remain forever locked there, preventing total BTP from\n * ever dropping below that value, and ensuring `_onInitializePool` can only be called once in the entire Pool's\n * lifetime.\n *\n * The tokens granted to the Pool will be transferred from `sender`. These amounts are considered upscaled and will\n * be downscaled (rounding up) before being returned to the Vault.\n */\n function _onInitializePool(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory scalingFactors,\n bytes memory userData\n ) internal virtual returns (uint256 bptAmountOut, uint256[] memory amountsIn);\n\n /**\n * @dev Called whenever the Pool is joined after the first initialization join (see `_onInitializePool`).\n *\n * Returns the amount of BPT to mint, the token amounts that the Pool will receive in return, and the number of\n * tokens to pay in protocol swap fees.\n *\n * Implementations of this function might choose to mutate the `balances` array to save gas (e.g. when\n * performing intermediate calculations, such as subtraction of due protocol fees). This can be done safely.\n *\n * Minted BPT will be sent to `recipient`.\n *\n * The tokens granted to the Pool will be transferred from `sender`. These amounts are considered upscaled and will\n * be downscaled (rounding up) before being returned to the Vault.\n *\n * Due protocol swap fees will be taken from the Pool's balance in the Vault (see `IBasePool.onJoinPool`). These\n * amounts are considered upscaled and will be downscaled (rounding down) before being returned to the Vault.\n */\n function _onJoinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n uint256[] memory scalingFactors,\n bytes memory userData\n )\n internal\n virtual\n returns (\n uint256 bptAmountOut,\n uint256[] memory amountsIn,\n uint256[] memory dueProtocolFeeAmounts\n );\n\n /**\n * @dev Called whenever the Pool is exited.\n *\n * Returns the amount of BPT to burn, the token amounts for each Pool token that the Pool will grant in return, and\n * the number of tokens to pay in protocol swap fees.\n *\n * Implementations of this function might choose to mutate the `balances` array to save gas (e.g. when\n * performing intermediate calculations, such as subtraction of due protocol fees). This can be done safely.\n *\n * BPT will be burnt from `sender`.\n *\n * The Pool will grant tokens to `recipient`. These amounts are considered upscaled and will be downscaled\n * (rounding down) before being returned to the Vault.\n *\n * Due protocol swap fees will be taken from the Pool's balance in the Vault (see `IBasePool.onExitPool`). These\n * amounts are considered upscaled and will be downscaled (rounding down) before being returned to the Vault.\n */\n function _onExitPool(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n uint256[] memory scalingFactors,\n bytes memory userData\n )\n internal\n virtual\n returns (\n uint256 bptAmountIn,\n uint256[] memory amountsOut,\n uint256[] memory dueProtocolFeeAmounts\n );\n\n // Internal functions\n\n /**\n * @dev Adds swap fee amount to `amount`, returning a higher value.\n */\n function _addSwapFeeAmount(uint256 amount) internal view returns (uint256) {\n // This returns amount + fee amount, so we round up (favoring a higher fee amount).\n return amount.divUp(FixedPoint.ONE.sub(getSwapFeePercentage()));\n }\n\n /**\n * @dev Subtracts swap fee amount from `amount`, returning a lower value.\n */\n function _subtractSwapFeeAmount(uint256 amount) internal view returns (uint256) {\n // This returns amount - fee amount, so we round up (favoring a higher fee amount).\n uint256 feeAmount = amount.mulUp(getSwapFeePercentage());\n return amount.sub(feeAmount);\n }\n\n // Scaling\n\n /**\n * @dev Returns a scaling factor that, when multiplied to a token amount for `token`, normalizes its balance as if\n * it had 18 decimals.\n */\n function _computeScalingFactor(IERC20 token) internal view returns (uint256) {\n // Tokens that don't implement the `decimals` method are not supported.\n uint256 tokenDecimals = ERC20(address(token)).decimals();\n\n // Tokens with more than 18 decimals are not supported.\n uint256 decimalsDifference = Math.sub(18, tokenDecimals);\n return FixedPoint.ONE * 10**decimalsDifference;\n }\n\n /**\n * @dev Returns the scaling factor for one of the Pool's tokens. Reverts if `token` is not a token registered by the\n * Pool.\n *\n * All scaling factors are fixed-point values with 18 decimals, to allow for this function to be overridden by\n * derived contracts that need to apply further scaling, making these factors potentially non-integer.\n *\n * The largest 'base' scaling factor (i.e. in tokens with less than 18 decimals) is 10**18, which in fixed-point is\n * 10**36. This value can be multiplied with a 112 bit Vault balance with no overflow by a factor of ~1e7, making\n * even relatively 'large' factors safe to use.\n *\n * The 1e7 figure is the result of 2**256 / (1e18 * 1e18 * 2**112).\n */\n function _scalingFactor(IERC20 token) internal view virtual returns (uint256);\n\n /**\n * @dev Same as `_scalingFactor()`, except for all registered tokens (in the same order as registered). The Vault\n * will always pass balances in this order when calling any of the Pool hooks.\n */\n function _scalingFactors() internal view virtual returns (uint256[] memory);\n\n function getScalingFactors() external view returns (uint256[] memory) {\n return _scalingFactors();\n }\n\n /**\n * @dev Applies `scalingFactor` to `amount`, resulting in a larger or equal value depending on whether it needed\n * scaling or not.\n */\n function _upscale(uint256 amount, uint256 scalingFactor) internal pure returns (uint256) {\n // Upscale rounding wouldn't necessarily always go in the same direction: in a swap for example the balance of\n // token in should be rounded up, and that of token out rounded down. This is the only place where we round in\n // the same direction for all amounts, as the impact of this rounding is expected to be minimal (and there's no\n // rounding error unless `_scalingFactor()` is overriden).\n return FixedPoint.mulDown(amount, scalingFactor);\n }\n\n /**\n * @dev Same as `_upscale`, but for an entire array. This function does not return anything, but instead *mutates*\n * the `amounts` array.\n */\n function _upscaleArray(uint256[] memory amounts, uint256[] memory scalingFactors) internal view {\n for (uint256 i = 0; i < _getTotalTokens(); ++i) {\n amounts[i] = FixedPoint.mulDown(amounts[i], scalingFactors[i]);\n }\n }\n\n /**\n * @dev Reverses the `scalingFactor` applied to `amount`, resulting in a smaller or equal value depending on\n * whether it needed scaling or not. The result is rounded down.\n */\n function _downscaleDown(uint256 amount, uint256 scalingFactor) internal pure returns (uint256) {\n return FixedPoint.divDown(amount, scalingFactor);\n }\n\n /**\n * @dev Same as `_downscaleDown`, but for an entire array. This function does not return anything, but instead\n * *mutates* the `amounts` array.\n */\n function _downscaleDownArray(uint256[] memory amounts, uint256[] memory scalingFactors) internal view {\n for (uint256 i = 0; i < _getTotalTokens(); ++i) {\n amounts[i] = FixedPoint.divDown(amounts[i], scalingFactors[i]);\n }\n }\n\n /**\n * @dev Reverses the `scalingFactor` applied to `amount`, resulting in a smaller or equal value depending on\n * whether it needed scaling or not. The result is rounded up.\n */\n function _downscaleUp(uint256 amount, uint256 scalingFactor) internal pure returns (uint256) {\n return FixedPoint.divUp(amount, scalingFactor);\n }\n\n /**\n * @dev Same as `_downscaleUp`, but for an entire array. This function does not return anything, but instead\n * *mutates* the `amounts` array.\n */\n function _downscaleUpArray(uint256[] memory amounts, uint256[] memory scalingFactors) internal view {\n for (uint256 i = 0; i < _getTotalTokens(); ++i) {\n amounts[i] = FixedPoint.divUp(amounts[i], scalingFactors[i]);\n }\n }\n\n function _getAuthorizer() internal view override returns (IAuthorizer) {\n // Access control management is delegated to the Vault's Authorizer. This lets Balancer Governance manage which\n // accounts can call permissioned functions: for example, to perform emergency pauses.\n // If the owner is delegated, then *all* permissioned functions, including `setSwapFeePercentage`, will be under\n // Governance control.\n return getVault().getAuthorizer();\n }\n\n function _queryAction(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n bytes memory userData,\n function(bytes32, address, address, uint256[] memory, uint256, uint256, uint256[] memory, bytes memory)\n internal\n returns (uint256, uint256[] memory, uint256[] memory) _action,\n function(uint256[] memory, uint256[] memory) internal view _downscaleArray\n ) private {\n // This uses the same technique used by the Vault in queryBatchSwap. Refer to that function for a detailed\n // explanation.\n\n if (msg.sender != address(this)) {\n // We perform an external call to ourselves, forwarding the same calldata. In this call, the else clause of\n // the preceding if statement will be executed instead.\n\n // solhint-disable-next-line avoid-low-level-calls\n (bool success, ) = address(this).call(msg.data);\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // This call should always revert to decode the bpt and token amounts from the revert reason\n switch success\n case 0 {\n // Note we are manually writing the memory slot 0. We can safely overwrite whatever is\n // stored there as we take full control of the execution and then immediately return.\n\n // We copy the first 4 bytes to check if it matches with the expected signature, otherwise\n // there was another revert reason and we should forward it.\n returndatacopy(0, 0, 0x04)\n let error := and(mload(0), 0xffffffff00000000000000000000000000000000000000000000000000000000)\n\n // If the first 4 bytes don't match with the expected signature, we forward the revert reason.\n if eq(eq(error, 0x43adbafb00000000000000000000000000000000000000000000000000000000), 0) {\n returndatacopy(0, 0, returndatasize())\n revert(0, returndatasize())\n }\n\n // The returndata contains the signature, followed by the raw memory representation of the\n // `bptAmount` and `tokenAmounts` (array: length + data). We need to return an ABI-encoded\n // representation of these.\n // An ABI-encoded response will include one additional field to indicate the starting offset of\n // the `tokenAmounts` array. The `bptAmount` will be laid out in the first word of the\n // returndata.\n //\n // In returndata:\n // [ signature ][ bptAmount ][ tokenAmounts length ][ tokenAmounts values ]\n // [ 4 bytes ][ 32 bytes ][ 32 bytes ][ (32 * length) bytes ]\n //\n // We now need to return (ABI-encoded values):\n // [ bptAmount ][ tokeAmounts offset ][ tokenAmounts length ][ tokenAmounts values ]\n // [ 32 bytes ][ 32 bytes ][ 32 bytes ][ (32 * length) bytes ]\n\n // We copy 32 bytes for the `bptAmount` from returndata into memory.\n // Note that we skip the first 4 bytes for the error signature\n returndatacopy(0, 0x04, 32)\n\n // The offsets are 32-bytes long, so the array of `tokenAmounts` will start after\n // the initial 64 bytes.\n mstore(0x20, 64)\n\n // We now copy the raw memory array for the `tokenAmounts` from returndata into memory.\n // Since bpt amount and offset take up 64 bytes, we start copying at address 0x40. We also\n // skip the first 36 bytes from returndata, which correspond to the signature plus bpt amount.\n returndatacopy(0x40, 0x24, sub(returndatasize(), 36))\n\n // We finally return the ABI-encoded uint256 and the array, which has a total length equal to\n // the size of returndata, plus the 32 bytes of the offset but without the 4 bytes of the\n // error signature.\n return(0, add(returndatasize(), 28))\n }\n default {\n // This call should always revert, but we fail nonetheless if that didn't happen\n invalid()\n }\n }\n } else {\n uint256[] memory scalingFactors = _scalingFactors();\n _upscaleArray(balances, scalingFactors);\n\n (uint256 bptAmount, uint256[] memory tokenAmounts, ) = _action(\n poolId,\n sender,\n recipient,\n balances,\n lastChangeBlock,\n protocolSwapFeePercentage,\n scalingFactors,\n userData\n );\n\n _downscaleArray(tokenAmounts, scalingFactors);\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n // We will return a raw representation of `bptAmount` and `tokenAmounts` in memory, which is composed of\n // a 32-byte uint256, followed by a 32-byte for the array length, and finally the 32-byte uint256 values\n // Because revert expects a size in bytes, we multiply the array length (stored at `tokenAmounts`) by 32\n let size := mul(mload(tokenAmounts), 32)\n\n // We store the `bptAmount` in the previous slot to the `tokenAmounts` array. We can make sure there\n // will be at least one available slot due to how the memory scratch space works.\n // We can safely overwrite whatever is stored in this slot as we will revert immediately after that.\n let start := sub(tokenAmounts, 0x20)\n mstore(start, bptAmount)\n\n // We send one extra value for the error signature \"QueryError(uint256,uint256[])\" which is 0x43adbafb\n // We use the previous slot to `bptAmount`.\n mstore(sub(start, 0x20), 0x0000000000000000000000000000000000000000000000000000000043adbafb)\n start := sub(start, 0x04)\n\n // When copying from `tokenAmounts` into returndata, we copy the additional 68 bytes to also return\n // the `bptAmount`, the array 's length, and the error signature.\n revert(start, add(size, 68))\n }\n }\n }\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IGeneralPool.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"./IBasePool.sol\";\n\n/**\n * @dev IPools with the General specialization setting should implement this interface.\n *\n * This is called by the Vault when a user calls `IVault.swap` or `IVault.batchSwap` to swap with this Pool.\n * Returns the number of tokens the Pool will grant to the user in a 'given in' swap, or that the user will\n * grant to the pool in a 'given out' swap.\n *\n * This can often be implemented by a `view` function, since many pricing algorithms don't need to track state\n * changes in swaps. However, contracts implementing this in non-view functions should check that the caller is\n * indeed the Vault.\n */\ninterface IGeneralPool is IBasePool {\n function onSwap(\n SwapRequest memory swapRequest,\n uint256[] memory balances,\n uint256 indexIn,\n uint256 indexOut\n ) external returns (uint256 amount);\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/math/Math.sol": {
- "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"../helpers/BalancerErrors.sol\";\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow checks.\n * Adapted from OpenZeppelin's SafeMath library\n */\nlibrary Math {\n /**\n * @dev Returns the addition of two unsigned integers of 256 bits, reverting on overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n _require(c >= a, Errors.ADD_OVERFLOW);\n return c;\n }\n\n /**\n * @dev Returns the addition of two signed integers, reverting on overflow.\n */\n function add(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a + b;\n _require((b >= 0 && c >= a) || (b < 0 && c < a), Errors.ADD_OVERFLOW);\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers of 256 bits, reverting on overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n _require(b <= a, Errors.SUB_OVERFLOW);\n uint256 c = a - b;\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two signed integers, reverting on overflow.\n */\n function sub(int256 a, int256 b) internal pure returns (int256) {\n int256 c = a - b;\n _require((b >= 0 && c <= a) || (b < 0 && c > a), Errors.SUB_OVERFLOW);\n return c;\n }\n\n /**\n * @dev Returns the largest of two numbers of 256 bits.\n */\n function max(uint256 a, uint256 b) internal pure returns (uint256) {\n return a >= b ? a : b;\n }\n\n /**\n * @dev Returns the smallest of two numbers of 256 bits.\n */\n function min(uint256 a, uint256 b) internal pure returns (uint256) {\n return a < b ? a : b;\n }\n\n function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a * b;\n _require(a == 0 || c / a == b, Errors.MUL_OVERFLOW);\n return c;\n }\n\n function div(\n uint256 a,\n uint256 b,\n bool roundUp\n ) internal pure returns (uint256) {\n return roundUp ? divUp(a, b) : divDown(a, b);\n }\n\n function divDown(uint256 a, uint256 b) internal pure returns (uint256) {\n _require(b != 0, Errors.ZERO_DIVISION);\n return a / b;\n }\n\n function divUp(uint256 a, uint256 b) internal pure returns (uint256) {\n _require(b != 0, Errors.ZERO_DIVISION);\n\n if (a == 0) {\n return 0;\n } else {\n return 1 + (a - 1) / b;\n }\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/TemporarilyPausable.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"./BalancerErrors.sol\";\nimport \"./ITemporarilyPausable.sol\";\n\n/**\n * @dev Allows for a contract to be paused during an initial period after deployment, disabling functionality. Can be\n * used as an emergency switch in case a security vulnerability or threat is identified.\n *\n * The contract can only be paused during the Pause Window, a period that starts at deployment. It can also be\n * unpaused and repaused any number of times during this period. This is intended to serve as a safety measure: it lets\n * system managers react quickly to potentially dangerous situations, knowing that this action is reversible if careful\n * analysis later determines there was a false alarm.\n *\n * If the contract is paused when the Pause Window finishes, it will remain in the paused state through an additional\n * Buffer Period, after which it will be automatically unpaused forever. This is to ensure there is always enough time\n * to react to an emergency, even if the threat is discovered shortly before the Pause Window expires.\n *\n * Note that since the contract can only be paused within the Pause Window, unpausing during the Buffer Period is\n * irreversible.\n */\nabstract contract TemporarilyPausable is ITemporarilyPausable {\n // The Pause Window and Buffer Period are timestamp-based: they should not be relied upon for sub-minute accuracy.\n // solhint-disable not-rely-on-time\n\n uint256 private constant _MAX_PAUSE_WINDOW_DURATION = 90 days;\n uint256 private constant _MAX_BUFFER_PERIOD_DURATION = 30 days;\n\n uint256 private immutable _pauseWindowEndTime;\n uint256 private immutable _bufferPeriodEndTime;\n\n bool private _paused;\n\n constructor(uint256 pauseWindowDuration, uint256 bufferPeriodDuration) {\n _require(pauseWindowDuration <= _MAX_PAUSE_WINDOW_DURATION, Errors.MAX_PAUSE_WINDOW_DURATION);\n _require(bufferPeriodDuration <= _MAX_BUFFER_PERIOD_DURATION, Errors.MAX_BUFFER_PERIOD_DURATION);\n\n uint256 pauseWindowEndTime = block.timestamp + pauseWindowDuration;\n\n _pauseWindowEndTime = pauseWindowEndTime;\n _bufferPeriodEndTime = pauseWindowEndTime + bufferPeriodDuration;\n }\n\n /**\n * @dev Reverts if the contract is paused.\n */\n modifier whenNotPaused() {\n _ensureNotPaused();\n _;\n }\n\n /**\n * @dev Returns the current contract pause status, as well as the end times of the Pause Window and Buffer\n * Period.\n */\n function getPausedState()\n external\n view\n override\n returns (\n bool paused,\n uint256 pauseWindowEndTime,\n uint256 bufferPeriodEndTime\n )\n {\n paused = !_isNotPaused();\n pauseWindowEndTime = _getPauseWindowEndTime();\n bufferPeriodEndTime = _getBufferPeriodEndTime();\n }\n\n /**\n * @dev Sets the pause state to `paused`. The contract can only be paused until the end of the Pause Window, and\n * unpaused until the end of the Buffer Period.\n *\n * Once the Buffer Period expires, this function reverts unconditionally.\n */\n function _setPaused(bool paused) internal {\n if (paused) {\n _require(block.timestamp < _getPauseWindowEndTime(), Errors.PAUSE_WINDOW_EXPIRED);\n } else {\n _require(block.timestamp < _getBufferPeriodEndTime(), Errors.BUFFER_PERIOD_EXPIRED);\n }\n\n _paused = paused;\n emit PausedStateChanged(paused);\n }\n\n /**\n * @dev Reverts if the contract is paused.\n */\n function _ensureNotPaused() internal view {\n _require(_isNotPaused(), Errors.PAUSED);\n }\n\n /**\n * @dev Returns true if the contract is unpaused.\n *\n * Once the Buffer Period expires, the gas cost of calling this function is reduced dramatically, as storage is no\n * longer accessed.\n */\n function _isNotPaused() internal view returns (bool) {\n // After the Buffer Period, the (inexpensive) timestamp check short-circuits the storage access.\n return block.timestamp > _getBufferPeriodEndTime() || !_paused;\n }\n\n // These getters lead to reduced bytecode size by inlining the immutable variables in a single place.\n\n function _getPauseWindowEndTime() private view returns (uint256) {\n return _pauseWindowEndTime;\n }\n\n function _getBufferPeriodEndTime() private view returns (uint256) {\n return _bufferPeriodEndTime;\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/WordCodec.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Library for encoding and decoding values stored inside a 256 bit word. Typically used to pack multiple values in\n * a single storage slot, saving gas by performing less storage accesses.\n *\n * Each value is defined by its size and the least significant bit in the word, also known as offset. For example, two\n * 128 bit values may be encoded in a word by assigning one an offset of 0, and the other an offset of 128.\n */\nlibrary WordCodec {\n // Masks are values with the least significant N bits set. They can be used to extract an encoded value from a word,\n // or to insert a new one replacing the old.\n uint256 private constant _MASK_1 = 2**(1) - 1;\n uint256 private constant _MASK_10 = 2**(10) - 1;\n uint256 private constant _MASK_16 = 2**(16) - 1;\n uint256 private constant _MASK_22 = 2**(22) - 1;\n uint256 private constant _MASK_31 = 2**(31) - 1;\n uint256 private constant _MASK_32 = 2**(32) - 1;\n uint256 private constant _MASK_53 = 2**(53) - 1;\n uint256 private constant _MASK_64 = 2**(64) - 1;\n uint256 private constant _MASK_128 = 2**(128) - 1;\n uint256 private constant _MASK_192 = 2**(192) - 1;\n\n // Largest positive values that can be represented as N bits signed integers.\n int256 private constant _MAX_INT_22 = 2**(21) - 1;\n int256 private constant _MAX_INT_53 = 2**(52) - 1;\n\n // In-place insertion\n\n /**\n * @dev Inserts a boolean value shifted by an offset into a 256 bit word, replacing the old value. Returns the new\n * word.\n */\n function insertBoolean(\n bytes32 word,\n bool value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_1 << offset));\n return clearedWord | bytes32(uint256(value ? 1 : 0) << offset);\n }\n\n // Unsigned\n\n /**\n * @dev Inserts a 10 bit unsigned integer shifted by an offset into a 256 bit word, replacing the old value. Returns\n * the new word.\n *\n * Assumes `value` only uses its least significant 10 bits, otherwise it may overwrite sibling bytes.\n */\n function insertUint10(\n bytes32 word,\n uint256 value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_10 << offset));\n return clearedWord | bytes32(value << offset);\n }\n\n /**\n * @dev Inserts a 16 bit unsigned integer shifted by an offset into a 256 bit word, replacing the old value.\n * Returns the new word.\n *\n * Assumes `value` only uses its least significant 16 bits, otherwise it may overwrite sibling bytes.\n */\n function insertUint16(\n bytes32 word,\n uint256 value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_16 << offset));\n return clearedWord | bytes32(value << offset);\n }\n\n /**\n * @dev Inserts a 31 bit unsigned integer shifted by an offset into a 256 bit word, replacing the old value. Returns\n * the new word.\n *\n * Assumes `value` can be represented using 31 bits.\n */\n function insertUint31(\n bytes32 word,\n uint256 value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_31 << offset));\n return clearedWord | bytes32(value << offset);\n }\n\n /**\n * @dev Inserts a 32 bit unsigned integer shifted by an offset into a 256 bit word, replacing the old value. Returns\n * the new word.\n *\n * Assumes `value` only uses its least significant 32 bits, otherwise it may overwrite sibling bytes.\n */\n function insertUint32(\n bytes32 word,\n uint256 value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_32 << offset));\n return clearedWord | bytes32(value << offset);\n }\n\n /**\n * @dev Inserts a 64 bit unsigned integer shifted by an offset into a 256 bit word, replacing the old value. Returns\n * the new word.\n *\n * Assumes `value` only uses its least significant 64 bits, otherwise it may overwrite sibling bytes.\n */\n function insertUint64(\n bytes32 word,\n uint256 value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_64 << offset));\n return clearedWord | bytes32(value << offset);\n }\n\n // Signed\n\n /**\n * @dev Inserts a 22 bits signed integer shifted by an offset into a 256 bit word, replacing the old value. Returns\n * the new word.\n *\n * Assumes `value` can be represented using 22 bits.\n */\n function insertInt22(\n bytes32 word,\n int256 value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_22 << offset));\n // Integer values need masking to remove the upper bits of negative values.\n return clearedWord | bytes32((uint256(value) & _MASK_22) << offset);\n }\n\n // Bytes\n\n /**\n * @dev Inserts 192 bit shifted by an offset into a 256 bit word, replacing the old value. Returns the new word.\n *\n * Assumes `value` can be represented using 192 bits.\n */\n function insertBits192(\n bytes32 word,\n bytes32 value,\n uint256 offset\n ) internal pure returns (bytes32) {\n bytes32 clearedWord = bytes32(uint256(word) & ~(_MASK_192 << offset));\n return clearedWord | bytes32((uint256(value) & _MASK_192) << offset);\n }\n\n // Encoding\n\n // Unsigned\n\n /**\n * @dev Encodes an unsigned integer shifted by an offset. This performs no size checks: it is up to the caller to\n * ensure that the values are bounded.\n *\n * The return value can be logically ORed with other encoded values to form a 256 bit word.\n */\n function encodeUint(uint256 value, uint256 offset) internal pure returns (bytes32) {\n return bytes32(value << offset);\n }\n\n // Signed\n\n /**\n * @dev Encodes a 22 bits signed integer shifted by an offset.\n *\n * The return value can be logically ORed with other encoded values to form a 256 bit word.\n */\n function encodeInt22(int256 value, uint256 offset) internal pure returns (bytes32) {\n // Integer values need masking to remove the upper bits of negative values.\n return bytes32((uint256(value) & _MASK_22) << offset);\n }\n\n /**\n * @dev Encodes a 53 bits signed integer shifted by an offset.\n *\n * The return value can be logically ORed with other encoded values to form a 256 bit word.\n */\n function encodeInt53(int256 value, uint256 offset) internal pure returns (bytes32) {\n // Integer values need masking to remove the upper bits of negative values.\n return bytes32((uint256(value) & _MASK_53) << offset);\n }\n\n // Decoding\n\n /**\n * @dev Decodes and returns a boolean shifted by an offset from a 256 bit word.\n */\n function decodeBool(bytes32 word, uint256 offset) internal pure returns (bool) {\n return (uint256(word >> offset) & _MASK_1) == 1;\n }\n\n // Unsigned\n\n /**\n * @dev Decodes and returns a 10 bit unsigned integer shifted by an offset from a 256 bit word.\n */\n function decodeUint10(bytes32 word, uint256 offset) internal pure returns (uint256) {\n return uint256(word >> offset) & _MASK_10;\n }\n\n /**\n * @dev Decodes and returns a 16 bit unsigned integer shifted by an offset from a 256 bit word.\n */\n function decodeUint16(bytes32 word, uint256 offset) internal pure returns (uint256) {\n return uint256(word >> offset) & _MASK_16;\n }\n\n /**\n * @dev Decodes and returns a 31 bit unsigned integer shifted by an offset from a 256 bit word.\n */\n function decodeUint31(bytes32 word, uint256 offset) internal pure returns (uint256) {\n return uint256(word >> offset) & _MASK_31;\n }\n\n /**\n * @dev Decodes and returns a 32 bit unsigned integer shifted by an offset from a 256 bit word.\n */\n function decodeUint32(bytes32 word, uint256 offset) internal pure returns (uint256) {\n return uint256(word >> offset) & _MASK_32;\n }\n\n /**\n * @dev Decodes and returns a 64 bit unsigned integer shifted by an offset from a 256 bit word.\n */\n function decodeUint64(bytes32 word, uint256 offset) internal pure returns (uint256) {\n return uint256(word >> offset) & _MASK_64;\n }\n\n /**\n * @dev Decodes and returns a 128 bit unsigned integer shifted by an offset from a 256 bit word.\n */\n function decodeUint128(bytes32 word, uint256 offset) internal pure returns (uint256) {\n return uint256(word >> offset) & _MASK_128;\n }\n\n // Signed\n\n /**\n * @dev Decodes and returns a 22 bits signed integer shifted by an offset from a 256 bit word.\n */\n function decodeInt22(bytes32 word, uint256 offset) internal pure returns (int256) {\n int256 value = int256(uint256(word >> offset) & _MASK_22);\n // In case the decoded value is greater than the max positive integer that can be represented with 22 bits,\n // we know it was originally a negative integer. Therefore, we mask it to restore the sign in the 256 bit\n // representation.\n return value > _MAX_INT_22 ? (value | int256(~_MASK_22)) : value;\n }\n\n /**\n * @dev Decodes and returns a 53 bits signed integer shifted by an offset from a 256 bit word.\n */\n function decodeInt53(bytes32 word, uint256 offset) internal pure returns (int256) {\n int256 value = int256(uint256(word >> offset) & _MASK_53);\n // In case the decoded value is greater than the max positive integer that can be represented with 53 bits,\n // we know it was originally a negative integer. Therefore, we mask it to restore the sign in the 256 bit\n // representation.\n\n return value > _MAX_INT_53 ? (value | int256(~_MASK_53)) : value;\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/ERC20.sol": {
- "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"../helpers/BalancerErrors.sol\";\n\nimport \"./IERC20.sol\";\nimport \"./SafeMath.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin guidelines: functions revert instead\n * of returning `false` on failure. This behavior is nonetheless conventional\n * and does not conflict with the expectations of ERC20 applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\ncontract ERC20 is IERC20 {\n using SafeMath for uint256;\n\n mapping(address => uint256) private _balances;\n\n mapping(address => mapping(address => uint256)) private _allowances;\n\n uint256 private _totalSupply;\n\n string private _name;\n string private _symbol;\n uint8 private _decimals;\n\n /**\n * @dev Sets the values for {name} and {symbol}, initializes {decimals} with\n * a default value of 18.\n *\n * To select a different value for {decimals}, use {_setupDecimals}.\n *\n * All three of these values are immutable: they can only be set once during\n * construction.\n */\n constructor(string memory name_, string memory symbol_) {\n _name = name_;\n _symbol = symbol_;\n _decimals = 18;\n }\n\n /**\n * @dev Returns the name of the token.\n */\n function name() public view returns (string memory) {\n return _name;\n }\n\n /**\n * @dev Returns the symbol of the token, usually a shorter version of the\n * name.\n */\n function symbol() public view returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev Returns the number of decimals used to get its user representation.\n * For example, if `decimals` equals `2`, a balance of `505` tokens should\n * be displayed to a user as `5,05` (`505 / 10 ** 2`).\n *\n * Tokens usually opt for a value of 18, imitating the relationship between\n * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is\n * called.\n *\n * NOTE: This information is only used for _display_ purposes: it in\n * no way affects any of the arithmetic of the contract, including\n * {IERC20-balanceOf} and {IERC20-transfer}.\n */\n function decimals() public view returns (uint8) {\n return _decimals;\n }\n\n /**\n * @dev See {IERC20-totalSupply}.\n */\n function totalSupply() public view override returns (uint256) {\n return _totalSupply;\n }\n\n /**\n * @dev See {IERC20-balanceOf}.\n */\n function balanceOf(address account) public view override returns (uint256) {\n return _balances[account];\n }\n\n /**\n * @dev See {IERC20-transfer}.\n *\n * Requirements:\n *\n * - `recipient` cannot be the zero address.\n * - the caller must have a balance of at least `amount`.\n */\n function transfer(address recipient, uint256 amount) public virtual override returns (bool) {\n _transfer(msg.sender, recipient, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-allowance}.\n */\n function allowance(address owner, address spender) public view virtual override returns (uint256) {\n return _allowances[owner][spender];\n }\n\n /**\n * @dev See {IERC20-approve}.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function approve(address spender, uint256 amount) public virtual override returns (bool) {\n _approve(msg.sender, spender, amount);\n return true;\n }\n\n /**\n * @dev See {IERC20-transferFrom}.\n *\n * Emits an {Approval} event indicating the updated allowance. This is not\n * required by the EIP. See the note at the beginning of {ERC20}.\n *\n * Requirements:\n *\n * - `sender` and `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n * - the caller must have allowance for ``sender``'s tokens of at least\n * `amount`.\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public virtual override returns (bool) {\n _transfer(sender, recipient, amount);\n _approve(\n sender,\n msg.sender,\n _allowances[sender][msg.sender].sub(amount, Errors.ERC20_TRANSFER_EXCEEDS_ALLOWANCE)\n );\n return true;\n }\n\n /**\n * @dev Atomically increases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n */\n function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {\n _approve(msg.sender, spender, _allowances[msg.sender][spender].add(addedValue));\n return true;\n }\n\n /**\n * @dev Atomically decreases the allowance granted to `spender` by the caller.\n *\n * This is an alternative to {approve} that can be used as a mitigation for\n * problems described in {IERC20-approve}.\n *\n * Emits an {Approval} event indicating the updated allowance.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `spender` must have allowance for the caller of at least\n * `subtractedValue`.\n */\n function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {\n _approve(\n msg.sender,\n spender,\n _allowances[msg.sender][spender].sub(subtractedValue, Errors.ERC20_DECREASED_ALLOWANCE_BELOW_ZERO)\n );\n return true;\n }\n\n /**\n * @dev Moves tokens `amount` from `sender` to `recipient`.\n *\n * This is internal function is equivalent to {transfer}, and can be used to\n * e.g. implement automatic token fees, slashing mechanisms, etc.\n *\n * Emits a {Transfer} event.\n *\n * Requirements:\n *\n * - `sender` cannot be the zero address.\n * - `recipient` cannot be the zero address.\n * - `sender` must have a balance of at least `amount`.\n */\n function _transfer(\n address sender,\n address recipient,\n uint256 amount\n ) internal virtual {\n _require(sender != address(0), Errors.ERC20_TRANSFER_FROM_ZERO_ADDRESS);\n _require(recipient != address(0), Errors.ERC20_TRANSFER_TO_ZERO_ADDRESS);\n\n _beforeTokenTransfer(sender, recipient, amount);\n\n _balances[sender] = _balances[sender].sub(amount, Errors.ERC20_TRANSFER_EXCEEDS_BALANCE);\n _balances[recipient] = _balances[recipient].add(amount);\n emit Transfer(sender, recipient, amount);\n }\n\n /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n * the total supply.\n *\n * Emits a {Transfer} event with `from` set to the zero address.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n */\n function _mint(address account, uint256 amount) internal virtual {\n _beforeTokenTransfer(address(0), account, amount);\n\n _totalSupply = _totalSupply.add(amount);\n _balances[account] = _balances[account].add(amount);\n emit Transfer(address(0), account, amount);\n }\n\n /**\n * @dev Destroys `amount` tokens from `account`, reducing the\n * total supply.\n *\n * Emits a {Transfer} event with `to` set to the zero address.\n *\n * Requirements:\n *\n * - `account` cannot be the zero address.\n * - `account` must have at least `amount` tokens.\n */\n function _burn(address account, uint256 amount) internal virtual {\n _require(account != address(0), Errors.ERC20_BURN_FROM_ZERO_ADDRESS);\n\n _beforeTokenTransfer(account, address(0), amount);\n\n _balances[account] = _balances[account].sub(amount, Errors.ERC20_BURN_EXCEEDS_ALLOWANCE);\n _totalSupply = _totalSupply.sub(amount);\n emit Transfer(account, address(0), amount);\n }\n\n /**\n * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n *\n * This internal function is equivalent to `approve`, and can be used to\n * e.g. set automatic allowances for certain subsystems, etc.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `owner` cannot be the zero address.\n * - `spender` cannot be the zero address.\n */\n function _approve(\n address owner,\n address spender,\n uint256 amount\n ) internal virtual {\n _allowances[owner][spender] = amount;\n emit Approval(owner, spender, amount);\n }\n\n /**\n * @dev Sets {decimals} to a value other than the default one of 18.\n *\n * WARNING: This function should only be called from the constructor. Most\n * applications that interact with token contracts will not expect\n * {decimals} to ever change, and may work incorrectly if it does.\n */\n function _setupDecimals(uint8 decimals_) internal {\n _decimals = decimals_;\n }\n\n /**\n * @dev Hook that is called before any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n * will be to transferred to `to`.\n * - when `from` is zero, `amount` tokens will be minted for `to`.\n * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 amount\n ) internal virtual {}\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IVault.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma experimental ABIEncoderV2;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/IERC20.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/helpers/ISignaturesValidator.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/helpers/ITemporarilyPausable.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/misc/IWETH.sol\";\n\nimport \"./IAsset.sol\";\nimport \"./IAuthorizer.sol\";\nimport \"./IFlashLoanRecipient.sol\";\nimport \"./IProtocolFeesCollector.sol\";\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Full external interface for the Vault core contract - no external or public methods exist in the contract that\n * don't override one of these declarations.\n */\ninterface IVault is ISignaturesValidator, ITemporarilyPausable {\n // Generalities about the Vault:\n //\n // - Whenever documentation refers to 'tokens', it strictly refers to ERC20-compliant token contracts. Tokens are\n // transferred out of the Vault by calling the `IERC20.transfer` function, and transferred in by calling\n // `IERC20.transferFrom`. In these cases, the sender must have previously allowed the Vault to use their tokens by\n // calling `IERC20.approve`. The only deviation from the ERC20 standard that is supported is functions not returning\n // a boolean value: in these scenarios, a non-reverting call is assumed to be successful.\n //\n // - All non-view functions in the Vault are non-reentrant: calling them while another one is mid-execution (e.g.\n // while execution control is transferred to a token contract during a swap) will result in a revert. View\n // functions can be called in a re-reentrant way, but doing so might cause them to return inconsistent results.\n // Contracts calling view functions in the Vault must make sure the Vault has not already been entered.\n //\n // - View functions revert if referring to either unregistered Pools, or unregistered tokens for registered Pools.\n\n // Authorizer\n //\n // Some system actions are permissioned, like setting and collecting protocol fees. This permissioning system exists\n // outside of the Vault in the Authorizer contract: the Vault simply calls the Authorizer to check if the caller\n // can perform a given action.\n\n /**\n * @dev Returns the Vault's Authorizer.\n */\n function getAuthorizer() external view returns (IAuthorizer);\n\n /**\n * @dev Sets a new Authorizer for the Vault. The caller must be allowed by the current Authorizer to do this.\n *\n * Emits an `AuthorizerChanged` event.\n */\n function setAuthorizer(IAuthorizer newAuthorizer) external;\n\n /**\n * @dev Emitted when a new authorizer is set by `setAuthorizer`.\n */\n event AuthorizerChanged(IAuthorizer indexed newAuthorizer);\n\n // Relayers\n //\n // Additionally, it is possible for an account to perform certain actions on behalf of another one, using their\n // Vault ERC20 allowance and Internal Balance. These accounts are said to be 'relayers' for these Vault functions,\n // and are expected to be smart contracts with sound authentication mechanisms. For an account to be able to wield\n // this power, two things must occur:\n // - The Authorizer must grant the account the permission to be a relayer for the relevant Vault function. This\n // means that Balancer governance must approve each individual contract to act as a relayer for the intended\n // functions.\n // - Each user must approve the relayer to act on their behalf.\n // This double protection means users cannot be tricked into approving malicious relayers (because they will not\n // have been allowed by the Authorizer via governance), nor can malicious relayers approved by a compromised\n // Authorizer or governance drain user funds, since they would also need to be approved by each individual user.\n\n /**\n * @dev Returns true if `user` has approved `relayer` to act as a relayer for them.\n */\n function hasApprovedRelayer(address user, address relayer) external view returns (bool);\n\n /**\n * @dev Allows `relayer` to act as a relayer for `sender` if `approved` is true, and disallows it otherwise.\n *\n * Emits a `RelayerApprovalChanged` event.\n */\n function setRelayerApproval(\n address sender,\n address relayer,\n bool approved\n ) external;\n\n /**\n * @dev Emitted every time a relayer is approved or disapproved by `setRelayerApproval`.\n */\n event RelayerApprovalChanged(address indexed relayer, address indexed sender, bool approved);\n\n // Internal Balance\n //\n // Users can deposit tokens into the Vault, where they are allocated to their Internal Balance, and later\n // transferred or withdrawn. It can also be used as a source of tokens when joining Pools, as a destination\n // when exiting them, and as either when performing swaps. This usage of Internal Balance results in greatly reduced\n // gas costs when compared to relying on plain ERC20 transfers, leading to large savings for frequent users.\n //\n // Internal Balance management features batching, which means a single contract call can be used to perform multiple\n // operations of different kinds, with different senders and recipients, at once.\n\n /**\n * @dev Returns `user`'s Internal Balance for a set of tokens.\n */\n function getInternalBalance(address user, IERC20[] memory tokens) external view returns (uint256[] memory);\n\n /**\n * @dev Performs a set of user balance operations, which involve Internal Balance (deposit, withdraw or transfer)\n * and plain ERC20 transfers using the Vault's allowance. This last feature is particularly useful for relayers, as\n * it lets integrators reuse a user's Vault allowance.\n *\n * For each operation, if the caller is not `sender`, it must be an authorized relayer for them.\n */\n function manageUserBalance(UserBalanceOp[] memory ops) external payable;\n\n /**\n * @dev Data for `manageUserBalance` operations, which include the possibility for ETH to be sent and received\n without manual WETH wrapping or unwrapping.\n */\n struct UserBalanceOp {\n UserBalanceOpKind kind;\n IAsset asset;\n uint256 amount;\n address sender;\n address payable recipient;\n }\n\n // There are four possible operations in `manageUserBalance`:\n //\n // - DEPOSIT_INTERNAL\n // Increases the Internal Balance of the `recipient` account by transferring tokens from the corresponding\n // `sender`. The sender must have allowed the Vault to use their tokens via `IERC20.approve()`.\n //\n // ETH can be used by passing the ETH sentinel value as the asset and forwarding ETH in the call: it will be wrapped\n // and deposited as WETH. Any ETH amount remaining will be sent back to the caller (not the sender, which is\n // relevant for relayers).\n //\n // Emits an `InternalBalanceChanged` event.\n //\n //\n // - WITHDRAW_INTERNAL\n // Decreases the Internal Balance of the `sender` account by transferring tokens to the `recipient`.\n //\n // ETH can be used by passing the ETH sentinel value as the asset. This will deduct WETH instead, unwrap it and send\n // it to the recipient as ETH.\n //\n // Emits an `InternalBalanceChanged` event.\n //\n //\n // - TRANSFER_INTERNAL\n // Transfers tokens from the Internal Balance of the `sender` account to the Internal Balance of `recipient`.\n //\n // Reverts if the ETH sentinel value is passed.\n //\n // Emits an `InternalBalanceChanged` event.\n //\n //\n // - TRANSFER_EXTERNAL\n // Transfers tokens from `sender` to `recipient`, using the Vault's ERC20 allowance. This is typically used by\n // relayers, as it lets them reuse a user's Vault allowance.\n //\n // Reverts if the ETH sentinel value is passed.\n //\n // Emits an `ExternalBalanceTransfer` event.\n\n enum UserBalanceOpKind { DEPOSIT_INTERNAL, WITHDRAW_INTERNAL, TRANSFER_INTERNAL, TRANSFER_EXTERNAL }\n\n /**\n * @dev Emitted when a user's Internal Balance changes, either from calls to `manageUserBalance`, or through\n * interacting with Pools using Internal Balance.\n *\n * Because Internal Balance works exclusively with ERC20 tokens, ETH deposits and withdrawals will use the WETH\n * address.\n */\n event InternalBalanceChanged(address indexed user, IERC20 indexed token, int256 delta);\n\n /**\n * @dev Emitted when a user's Vault ERC20 allowance is used by the Vault to transfer tokens to an external account.\n */\n event ExternalBalanceTransfer(IERC20 indexed token, address indexed sender, address recipient, uint256 amount);\n\n // Pools\n //\n // There are three specialization settings for Pools, which allow for cheaper swaps at the cost of reduced\n // functionality:\n //\n // - General: no specialization, suited for all Pools. IGeneralPool is used for swap request callbacks, passing the\n // balance of all tokens in the Pool. These Pools have the largest swap costs (because of the extra storage reads),\n // which increase with the number of registered tokens.\n //\n // - Minimal Swap Info: IMinimalSwapInfoPool is used instead of IGeneralPool, which saves gas by only passing the\n // balance of the two tokens involved in the swap. This is suitable for some pricing algorithms, like the weighted\n // constant product one popularized by Balancer V1. Swap costs are smaller compared to general Pools, and are\n // independent of the number of registered tokens.\n //\n // - Two Token: only allows two tokens to be registered. This achieves the lowest possible swap gas cost. Like\n // minimal swap info Pools, these are called via IMinimalSwapInfoPool.\n\n enum PoolSpecialization { GENERAL, MINIMAL_SWAP_INFO, TWO_TOKEN }\n\n /**\n * @dev Registers the caller account as a Pool with a given specialization setting. Returns the Pool's ID, which\n * is used in all Pool-related functions. Pools cannot be deregistered, nor can the Pool's specialization be\n * changed.\n *\n * The caller is expected to be a smart contract that implements either `IGeneralPool` or `IMinimalSwapInfoPool`,\n * depending on the chosen specialization setting. This contract is known as the Pool's contract.\n *\n * Note that the same contract may register itself as multiple Pools with unique Pool IDs, or in other words,\n * multiple Pools may share the same contract.\n *\n * Emits a `PoolRegistered` event.\n */\n function registerPool(PoolSpecialization specialization) external returns (bytes32);\n\n /**\n * @dev Emitted when a Pool is registered by calling `registerPool`.\n */\n event PoolRegistered(bytes32 indexed poolId, address indexed poolAddress, PoolSpecialization specialization);\n\n /**\n * @dev Returns a Pool's contract address and specialization setting.\n */\n function getPool(bytes32 poolId) external view returns (address, PoolSpecialization);\n\n /**\n * @dev Registers `tokens` for the `poolId` Pool. Must be called by the Pool's contract.\n *\n * Pools can only interact with tokens they have registered. Users join a Pool by transferring registered tokens,\n * exit by receiving registered tokens, and can only swap registered tokens.\n *\n * Each token can only be registered once. For Pools with the Two Token specialization, `tokens` must have a length\n * of two, that is, both tokens must be registered in the same `registerTokens` call, and they must be sorted in\n * ascending order.\n *\n * The `tokens` and `assetManagers` arrays must have the same length, and each entry in these indicates the Asset\n * Manager for the corresponding token. Asset Managers can manage a Pool's tokens via `managePoolBalance`,\n * depositing and withdrawing them directly, and can even set their balance to arbitrary amounts. They are therefore\n * expected to be highly secured smart contracts with sound design principles, and the decision to register an\n * Asset Manager should not be made lightly.\n *\n * Pools can choose not to assign an Asset Manager to a given token by passing in the zero address. Once an Asset\n * Manager is set, it cannot be changed except by deregistering the associated token and registering again with a\n * different Asset Manager.\n *\n * Emits a `TokensRegistered` event.\n */\n function registerTokens(\n bytes32 poolId,\n IERC20[] memory tokens,\n address[] memory assetManagers\n ) external;\n\n /**\n * @dev Emitted when a Pool registers tokens by calling `registerTokens`.\n */\n event TokensRegistered(bytes32 indexed poolId, IERC20[] tokens, address[] assetManagers);\n\n /**\n * @dev Deregisters `tokens` for the `poolId` Pool. Must be called by the Pool's contract.\n *\n * Only registered tokens (via `registerTokens`) can be deregistered. Additionally, they must have zero total\n * balance. For Pools with the Two Token specialization, `tokens` must have a length of two, that is, both tokens\n * must be deregistered in the same `deregisterTokens` call.\n *\n * A deregistered token can be re-registered later on, possibly with a different Asset Manager.\n *\n * Emits a `TokensDeregistered` event.\n */\n function deregisterTokens(bytes32 poolId, IERC20[] memory tokens) external;\n\n /**\n * @dev Emitted when a Pool deregisters tokens by calling `deregisterTokens`.\n */\n event TokensDeregistered(bytes32 indexed poolId, IERC20[] tokens);\n\n /**\n * @dev Returns detailed information for a Pool's registered token.\n *\n * `cash` is the number of tokens the Vault currently holds for the Pool. `managed` is the number of tokens\n * withdrawn and held outside the Vault by the Pool's token Asset Manager. The Pool's total balance for `token`\n * equals the sum of `cash` and `managed`.\n *\n * Internally, `cash` and `managed` are stored using 112 bits. No action can ever cause a Pool's token `cash`,\n * `managed` or `total` balance to be greater than 2^112 - 1.\n *\n * `lastChangeBlock` is the number of the block in which `token`'s total balance was last modified (via either a\n * join, exit, swap, or Asset Manager update). This value is useful to avoid so-called 'sandwich attacks', for\n * example when developing price oracles. A change of zero (e.g. caused by a swap with amount zero) is considered a\n * change for this purpose, and will update `lastChangeBlock`.\n *\n * `assetManager` is the Pool's token Asset Manager.\n */\n function getPoolTokenInfo(bytes32 poolId, IERC20 token)\n external\n view\n returns (\n uint256 cash,\n uint256 managed,\n uint256 lastChangeBlock,\n address assetManager\n );\n\n /**\n * @dev Returns a Pool's registered tokens, the total balance for each, and the latest block when *any* of\n * the tokens' `balances` changed.\n *\n * The order of the `tokens` array is the same order that will be used in `joinPool`, `exitPool`, as well as in all\n * Pool hooks (where applicable). Calls to `registerTokens` and `deregisterTokens` may change this order.\n *\n * If a Pool only registers tokens once, and these are sorted in ascending order, they will be stored in the same\n * order as passed to `registerTokens`.\n *\n * Total balances include both tokens held by the Vault and those withdrawn by the Pool's Asset Managers. These are\n * the amounts used by joins, exits and swaps. For a detailed breakdown of token balances, use `getPoolTokenInfo`\n * instead.\n */\n function getPoolTokens(bytes32 poolId)\n external\n view\n returns (\n IERC20[] memory tokens,\n uint256[] memory balances,\n uint256 lastChangeBlock\n );\n\n /**\n * @dev Called by users to join a Pool, which transfers tokens from `sender` into the Pool's balance. This will\n * trigger custom Pool behavior, which will typically grant something in return to `recipient` - often tokenized\n * Pool shares.\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `assets` and `maxAmountsIn` arrays must have the same length, and each entry indicates the maximum amount\n * to send for each asset. The amounts to send are decided by the Pool and not the Vault: it just enforces\n * these maximums.\n *\n * If joining a Pool that holds WETH, it is possible to send ETH directly: the Vault will do the wrapping. To enable\n * this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead of the\n * WETH address. Note that it is not possible to combine ETH and WETH in the same join. Any excess ETH will be sent\n * back to the caller (not the sender, which is important for relayers).\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If sending ETH however, the array must be\n * sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the final\n * `assets` array might not be sorted. Pools with no registered tokens cannot be joined.\n *\n * If `fromInternalBalance` is true, the caller's Internal Balance will be preferred: ERC20 transfers will only\n * be made for the difference between the requested amount and Internal Balance (if any). Note that ETH cannot be\n * withdrawn from Internal Balance: attempting to do so will trigger a revert.\n *\n * This causes the Vault to call the `IBasePool.onJoinPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares). This can be encoded in the `userData` argument, which is ignored by the Vault and passed\n * directly to the Pool's contract, as is `recipient`.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function joinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n JoinPoolRequest memory request\n ) external payable;\n\n struct JoinPoolRequest {\n IAsset[] assets;\n uint256[] maxAmountsIn;\n bytes userData;\n bool fromInternalBalance;\n }\n\n /**\n * @dev Called by users to exit a Pool, which transfers tokens from the Pool's balance to `recipient`. This will\n * trigger custom Pool behavior, which will typically ask for something in return from `sender` - often tokenized\n * Pool shares. The amount of tokens that can be withdrawn is limited by the Pool's `cash` balance (see\n * `getPoolTokenInfo`).\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * The `tokens` and `minAmountsOut` arrays must have the same length, and each entry in these indicates the minimum\n * token amount to receive for each token contract. The amounts to send are decided by the Pool and not the Vault:\n * it just enforces these minimums.\n *\n * If exiting a Pool that holds WETH, it is possible to receive ETH directly: the Vault will do the unwrapping. To\n * enable this mechanism, the IAsset sentinel value (the zero address) must be passed in the `assets` array instead\n * of the WETH address. Note that it is not possible to combine ETH and WETH in the same exit.\n *\n * `assets` must have the same length and order as the array returned by `getPoolTokens`. This prevents issues when\n * interacting with Pools that register and deregister tokens frequently. If receiving ETH however, the array must\n * be sorted *before* replacing the WETH address with the ETH sentinel value (the zero address), which means the\n * final `assets` array might not be sorted. Pools with no registered tokens cannot be exited.\n *\n * If `toInternalBalance` is true, the tokens will be deposited to `recipient`'s Internal Balance. Otherwise,\n * an ERC20 transfer will be performed. Note that ETH cannot be deposited to Internal Balance: attempting to\n * do so will trigger a revert.\n *\n * `minAmountsOut` is the minimum amount of tokens the user expects to get out of the Pool, for each token in the\n * `tokens` array. This array must match the Pool's registered tokens.\n *\n * This causes the Vault to call the `IBasePool.onExitPool` hook on the Pool's contract, where Pools implement\n * their own custom logic. This typically requires additional information from the user (such as the expected number\n * of Pool shares to return). This can be encoded in the `userData` argument, which is ignored by the Vault and\n * passed directly to the Pool's contract.\n *\n * Emits a `PoolBalanceChanged` event.\n */\n function exitPool(\n bytes32 poolId,\n address sender,\n address payable recipient,\n ExitPoolRequest memory request\n ) external;\n\n struct ExitPoolRequest {\n IAsset[] assets;\n uint256[] minAmountsOut;\n bytes userData;\n bool toInternalBalance;\n }\n\n /**\n * @dev Emitted when a user joins or exits a Pool by calling `joinPool` or `exitPool`, respectively.\n */\n event PoolBalanceChanged(\n bytes32 indexed poolId,\n address indexed liquidityProvider,\n IERC20[] tokens,\n int256[] deltas,\n uint256[] protocolFeeAmounts\n );\n\n enum PoolBalanceChangeKind { JOIN, EXIT }\n\n // Swaps\n //\n // Users can swap tokens with Pools by calling the `swap` and `batchSwap` functions. To do this,\n // they need not trust Pool contracts in any way: all security checks are made by the Vault. They must however be\n // aware of the Pools' pricing algorithms in order to estimate the prices Pools will quote.\n //\n // The `swap` function executes a single swap, while `batchSwap` can perform multiple swaps in sequence.\n // In each individual swap, tokens of one kind are sent from the sender to the Pool (this is the 'token in'),\n // and tokens of another kind are sent from the Pool to the recipient in exchange (this is the 'token out').\n // More complex swaps, such as one token in to multiple tokens out can be achieved by batching together\n // individual swaps.\n //\n // There are two swap kinds:\n // - 'given in' swaps, where the amount of tokens in (sent to the Pool) is known, and the Pool determines (via the\n // `onSwap` hook) the amount of tokens out (to send to the recipient).\n // - 'given out' swaps, where the amount of tokens out (received from the Pool) is known, and the Pool determines\n // (via the `onSwap` hook) the amount of tokens in (to receive from the sender).\n //\n // Additionally, it is possible to chain swaps using a placeholder input amount, which the Vault replaces with\n // the calculated output of the previous swap. If the previous swap was 'given in', this will be the calculated\n // tokenOut amount. If the previous swap was 'given out', it will use the calculated tokenIn amount. These extended\n // swaps are known as 'multihop' swaps, since they 'hop' through a number of intermediate tokens before arriving at\n // the final intended token.\n //\n // In all cases, tokens are only transferred in and out of the Vault (or withdrawn from and deposited into Internal\n // Balance) after all individual swaps have been completed, and the net token balance change computed. This makes\n // certain swap patterns, such as multihops, or swaps that interact with the same token pair in multiple Pools, cost\n // much less gas than they would otherwise.\n //\n // It also means that under certain conditions it is possible to perform arbitrage by swapping with multiple\n // Pools in a way that results in net token movement out of the Vault (profit), with no tokens being sent in (only\n // updating the Pool's internal accounting).\n //\n // To protect users from front-running or the market changing rapidly, they supply a list of 'limits' for each token\n // involved in the swap, where either the maximum number of tokens to send (by passing a positive value) or the\n // minimum amount of tokens to receive (by passing a negative value) is specified.\n //\n // Additionally, a 'deadline' timestamp can also be provided, forcing the swap to fail if it occurs after\n // this point in time (e.g. if the transaction failed to be included in a block promptly).\n //\n // If interacting with Pools that hold WETH, it is possible to both send and receive ETH directly: the Vault will do\n // the wrapping and unwrapping. To enable this mechanism, the IAsset sentinel value (the zero address) must be\n // passed in the `assets` array instead of the WETH address. Note that it is possible to combine ETH and WETH in the\n // same swap. Any excess ETH will be sent back to the caller (not the sender, which is relevant for relayers).\n //\n // Finally, Internal Balance can be used when either sending or receiving tokens.\n\n enum SwapKind { GIVEN_IN, GIVEN_OUT }\n\n /**\n * @dev Performs a swap with a single Pool.\n *\n * If the swap is 'given in' (the number of tokens to send to the Pool is known), it returns the amount of tokens\n * taken from the Pool, which must be greater than or equal to `limit`.\n *\n * If the swap is 'given out' (the number of tokens to take from the Pool is known), it returns the amount of tokens\n * sent to the Pool, which must be less than or equal to `limit`.\n *\n * Internal Balance usage and the recipient are determined by the `funds` struct.\n *\n * Emits a `Swap` event.\n */\n function swap(\n SingleSwap memory singleSwap,\n FundManagement memory funds,\n uint256 limit,\n uint256 deadline\n ) external payable returns (uint256);\n\n /**\n * @dev Data for a single swap executed by `swap`. `amount` is either `amountIn` or `amountOut` depending on\n * the `kind` value.\n *\n * `assetIn` and `assetOut` are either token addresses, or the IAsset sentinel value for ETH (the zero address).\n * Note that Pools never interact with ETH directly: it will be wrapped to or unwrapped from WETH by the Vault.\n *\n * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be\n * used to extend swap behavior.\n */\n struct SingleSwap {\n bytes32 poolId;\n SwapKind kind;\n IAsset assetIn;\n IAsset assetOut;\n uint256 amount;\n bytes userData;\n }\n\n /**\n * @dev Performs a series of swaps with one or multiple Pools. In each individual swap, the caller determines either\n * the amount of tokens sent to or received from the Pool, depending on the `kind` value.\n *\n * Returns an array with the net Vault asset balance deltas. Positive amounts represent tokens (or ETH) sent to the\n * Vault, and negative amounts represent tokens (or ETH) sent by the Vault. Each delta corresponds to the asset at\n * the same index in the `assets` array.\n *\n * Swaps are executed sequentially, in the order specified by the `swaps` array. Each array element describes a\n * Pool, the token to be sent to this Pool, the token to receive from it, and an amount that is either `amountIn` or\n * `amountOut` depending on the swap kind.\n *\n * Multihop swaps can be executed by passing an `amount` value of zero for a swap. This will cause the amount in/out\n * of the previous swap to be used as the amount in for the current one. In a 'given in' swap, 'tokenIn' must equal\n * the previous swap's `tokenOut`. For a 'given out' swap, `tokenOut` must equal the previous swap's `tokenIn`.\n *\n * The `assets` array contains the addresses of all assets involved in the swaps. These are either token addresses,\n * or the IAsset sentinel value for ETH (the zero address). Each entry in the `swaps` array specifies tokens in and\n * out by referencing an index in `assets`. Note that Pools never interact with ETH directly: it will be wrapped to\n * or unwrapped from WETH by the Vault.\n *\n * Internal Balance usage, sender, and recipient are determined by the `funds` struct. The `limits` array specifies\n * the minimum or maximum amount of each token the vault is allowed to transfer.\n *\n * `batchSwap` can be used to make a single swap, like `swap` does, but doing so requires more gas than the\n * equivalent `swap` call.\n *\n * Emits `Swap` events.\n */\n function batchSwap(\n SwapKind kind,\n BatchSwapStep[] memory swaps,\n IAsset[] memory assets,\n FundManagement memory funds,\n int256[] memory limits,\n uint256 deadline\n ) external payable returns (int256[] memory);\n\n /**\n * @dev Data for each individual swap executed by `batchSwap`. The asset in and out fields are indexes into the\n * `assets` array passed to that function, and ETH assets are converted to WETH.\n *\n * If `amount` is zero, the multihop mechanism is used to determine the actual amount based on the amount in/out\n * from the previous swap, depending on the swap kind.\n *\n * The `userData` field is ignored by the Vault, but forwarded to the Pool in the `onSwap` hook, and may be\n * used to extend swap behavior.\n */\n struct BatchSwapStep {\n bytes32 poolId;\n uint256 assetInIndex;\n uint256 assetOutIndex;\n uint256 amount;\n bytes userData;\n }\n\n /**\n * @dev Emitted for each individual swap performed by `swap` or `batchSwap`.\n */\n event Swap(\n bytes32 indexed poolId,\n IERC20 indexed tokenIn,\n IERC20 indexed tokenOut,\n uint256 amountIn,\n uint256 amountOut\n );\n\n /**\n * @dev All tokens in a swap are either sent from the `sender` account to the Vault, or from the Vault to the\n * `recipient` account.\n *\n * If the caller is not `sender`, it must be an authorized relayer for them.\n *\n * If `fromInternalBalance` is true, the `sender`'s Internal Balance will be preferred, performing an ERC20\n * transfer for the difference between the requested amount and the User's Internal Balance (if any). The `sender`\n * must have allowed the Vault to use their tokens via `IERC20.approve()`. This matches the behavior of\n * `joinPool`.\n *\n * If `toInternalBalance` is true, tokens will be deposited to `recipient`'s internal balance instead of\n * transferred. This matches the behavior of `exitPool`.\n *\n * Note that ETH cannot be deposited to or withdrawn from Internal Balance: attempting to do so will trigger a\n * revert.\n */\n struct FundManagement {\n address sender;\n bool fromInternalBalance;\n address payable recipient;\n bool toInternalBalance;\n }\n\n /**\n * @dev Simulates a call to `batchSwap`, returning an array of Vault asset deltas. Calls to `swap` cannot be\n * simulated directly, but an equivalent `batchSwap` call can and will yield the exact same result.\n *\n * Each element in the array corresponds to the asset at the same index, and indicates the number of tokens (or ETH)\n * the Vault would take from the sender (if positive) or send to the recipient (if negative). The arguments it\n * receives are the same that an equivalent `batchSwap` call would receive.\n *\n * Unlike `batchSwap`, this function performs no checks on the sender or recipient field in the `funds` struct.\n * This makes it suitable to be called by off-chain applications via eth_call without needing to hold tokens,\n * approve them for the Vault, or even know a user's address.\n *\n * Note that this function is not 'view' (due to implementation details): the client code must explicitly execute\n * eth_call instead of eth_sendTransaction.\n */\n function queryBatchSwap(\n SwapKind kind,\n BatchSwapStep[] memory swaps,\n IAsset[] memory assets,\n FundManagement memory funds\n ) external returns (int256[] memory assetDeltas);\n\n // Flash Loans\n\n /**\n * @dev Performs a 'flash loan', sending tokens to `recipient`, executing the `receiveFlashLoan` hook on it,\n * and then reverting unless the tokens plus a proportional protocol fee have been returned.\n *\n * The `tokens` and `amounts` arrays must have the same length, and each entry in these indicates the loan amount\n * for each token contract. `tokens` must be sorted in ascending order.\n *\n * The 'userData' field is ignored by the Vault, and forwarded as-is to `recipient` as part of the\n * `receiveFlashLoan` call.\n *\n * Emits `FlashLoan` events.\n */\n function flashLoan(\n IFlashLoanRecipient recipient,\n IERC20[] memory tokens,\n uint256[] memory amounts,\n bytes memory userData\n ) external;\n\n /**\n * @dev Emitted for each individual flash loan performed by `flashLoan`.\n */\n event FlashLoan(IFlashLoanRecipient indexed recipient, IERC20 indexed token, uint256 amount, uint256 feeAmount);\n\n // Asset Management\n //\n // Each token registered for a Pool can be assigned an Asset Manager, which is able to freely withdraw the Pool's\n // tokens from the Vault, deposit them, or assign arbitrary values to its `managed` balance (see\n // `getPoolTokenInfo`). This makes them extremely powerful and dangerous. Even if an Asset Manager only directly\n // controls one of the tokens in a Pool, a malicious manager could set that token's balance to manipulate the\n // prices of the other tokens, and then drain the Pool with swaps. The risk of using Asset Managers is therefore\n // not constrained to the tokens they are managing, but extends to the entire Pool's holdings.\n //\n // However, a properly designed Asset Manager smart contract can be safely used for the Pool's benefit,\n // for example by lending unused tokens out for interest, or using them to participate in voting protocols.\n //\n // This concept is unrelated to the IAsset interface.\n\n /**\n * @dev Performs a set of Pool balance operations, which may be either withdrawals, deposits or updates.\n *\n * Pool Balance management features batching, which means a single contract call can be used to perform multiple\n * operations of different kinds, with different Pools and tokens, at once.\n *\n * For each operation, the caller must be registered as the Asset Manager for `token` in `poolId`.\n */\n function managePoolBalance(PoolBalanceOp[] memory ops) external;\n\n struct PoolBalanceOp {\n PoolBalanceOpKind kind;\n bytes32 poolId;\n IERC20 token;\n uint256 amount;\n }\n\n /**\n * Withdrawals decrease the Pool's cash, but increase its managed balance, leaving the total balance unchanged.\n *\n * Deposits increase the Pool's cash, but decrease its managed balance, leaving the total balance unchanged.\n *\n * Updates don't affect the Pool's cash balance, but because the managed balance changes, it does alter the total.\n * The external amount can be either increased or decreased by this call (i.e., reporting a gain or a loss).\n */\n enum PoolBalanceOpKind { WITHDRAW, DEPOSIT, UPDATE }\n\n /**\n * @dev Emitted when a Pool's token Asset Manager alters its balance via `managePoolBalance`.\n */\n event PoolBalanceManaged(\n bytes32 indexed poolId,\n address indexed assetManager,\n IERC20 indexed token,\n int256 cashDelta,\n int256 managedDelta\n );\n\n // Protocol Fees\n //\n // Some operations cause the Vault to collect tokens in the form of protocol fees, which can then be withdrawn by\n // permissioned accounts.\n //\n // There are two kinds of protocol fees:\n //\n // - flash loan fees: charged on all flash loans, as a percentage of the amounts lent.\n //\n // - swap fees: a percentage of the fees charged by Pools when performing swaps. For a number of reasons, including\n // swap gas costs and interface simplicity, protocol swap fees are not charged on each individual swap. Rather,\n // Pools are expected to keep track of how much they have charged in swap fees, and pay any outstanding debts to the\n // Vault when they are joined or exited. This prevents users from joining a Pool with unpaid debt, as well as\n // exiting a Pool in debt without first paying their share.\n\n /**\n * @dev Returns the current protocol fee module.\n */\n function getProtocolFeesCollector() external view returns (IProtocolFeesCollector);\n\n /**\n * @dev Safety mechanism to pause most Vault operations in the event of an emergency - typically detection of an\n * error in some part of the system.\n *\n * The Vault can only be paused during an initial time period, after which pausing is forever disabled.\n *\n * While the contract is paused, the following features are disabled:\n * - depositing and transferring internal balance\n * - transferring external balance (using the Vault's allowance)\n * - swaps\n * - joining Pools\n * - Asset Manager interactions\n *\n * Internal Balance can still be withdrawn, and Pools exited.\n */\n function setPaused(bool paused) external;\n\n /**\n * @dev Returns the Vault's WETH instance.\n */\n function WETH() external view returns (IWETH);\n // solhint-disable-previous-line func-name-mixedcase\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IBasePool.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"./IVault.sol\";\nimport \"./IPoolSwapStructs.sol\";\n\n/**\n * @dev Interface for adding and removing liquidity that all Pool contracts should implement. Note that this is not\n * the complete Pool contract interface, as it is missing the swap hooks. Pool contracts should also inherit from\n * either IGeneralPool or IMinimalSwapInfoPool\n */\ninterface IBasePool is IPoolSwapStructs {\n /**\n * @dev Called by the Vault when a user calls `IVault.joinPool` to add liquidity to this Pool. Returns how many of\n * each registered token the user should provide, as well as the amount of protocol fees the Pool owes to the Vault.\n * The Vault will then take tokens from `sender` and add them to the Pool's balances, as well as collect\n * the reported amount in protocol fees, which the pool should calculate based on `protocolSwapFeePercentage`.\n *\n * Protocol fees are reported and charged on join events so that the Pool is free of debt whenever new users join.\n *\n * `sender` is the account performing the join (from which tokens will be withdrawn), and `recipient` is the account\n * designated to receive any benefits (typically pool shares). `balances` contains the total balances\n * for each token the Pool registered in the Vault, in the same order that `IVault.getPoolTokens` would return.\n *\n * `lastChangeBlock` is the last block in which *any* of the Pool's registered tokens last changed its total\n * balance.\n *\n * `userData` contains any pool-specific instructions needed to perform the calculations, such as the type of\n * join (e.g., proportional given an amount of pool shares, single-asset, multi-asset, etc.)\n *\n * Contracts implementing this function should check that the caller is indeed the Vault before performing any\n * state-changing operations, such as minting pool shares.\n */\n function onJoinPool(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n bytes memory userData\n ) external returns (uint256[] memory amountsIn, uint256[] memory dueProtocolFeeAmounts);\n\n /**\n * @dev Called by the Vault when a user calls `IVault.exitPool` to remove liquidity from this Pool. Returns how many\n * tokens the Vault should deduct from the Pool's balances, as well as the amount of protocol fees the Pool owes\n * to the Vault. The Vault will then take tokens from the Pool's balances and send them to `recipient`,\n * as well as collect the reported amount in protocol fees, which the Pool should calculate based on\n * `protocolSwapFeePercentage`.\n *\n * Protocol fees are charged on exit events to guarantee that users exiting the Pool have paid their share.\n *\n * `sender` is the account performing the exit (typically the pool shareholder), and `recipient` is the account\n * to which the Vault will send the proceeds. `balances` contains the total token balances for each token\n * the Pool registered in the Vault, in the same order that `IVault.getPoolTokens` would return.\n *\n * `lastChangeBlock` is the last block in which *any* of the Pool's registered tokens last changed its total\n * balance.\n *\n * `userData` contains any pool-specific instructions needed to perform the calculations, such as the type of\n * exit (e.g., proportional given an amount of pool shares, single-asset, multi-asset, etc.)\n *\n * Contracts implementing this function should check that the caller is indeed the Vault before performing any\n * state-changing operations, such as burning pool shares.\n */\n function onExitPool(\n bytes32 poolId,\n address sender,\n address recipient,\n uint256[] memory balances,\n uint256 lastChangeBlock,\n uint256 protocolSwapFeePercentage,\n bytes memory userData\n ) external returns (uint256[] memory amountsOut, uint256[] memory dueProtocolFeeAmounts);\n\n function getPoolId() external view returns (bytes32);\n}\n"
- },
- "@balancer-labs/v2-asset-manager-utils/contracts/IAssetManager.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/IERC20.sol\";\n\ninterface IAssetManager {\n /**\n * @notice Emitted when asset manager is rebalanced\n */\n event Rebalance(bytes32 poolId);\n\n /**\n * @notice Sets the config\n */\n function setConfig(bytes32 poolId, bytes calldata config) external;\n\n /**\n * Note: No function to read the asset manager config is included in IAssetManager\n * as the signature is expected to vary between asset manager implementations\n */\n\n /**\n * @notice Returns the asset manager's token\n */\n function getToken() external view returns (IERC20);\n\n /**\n * @return the current assets under management of this asset manager\n */\n function getAUM(bytes32 poolId) external view returns (uint256);\n\n /**\n * @return poolCash - The up-to-date cash balance of the pool\n * @return poolManaged - The up-to-date managed balance of the pool\n */\n function getPoolBalances(bytes32 poolId) external view returns (uint256 poolCash, uint256 poolManaged);\n\n /**\n * @return The difference in tokens between the target investment\n * and the currently invested amount (i.e. the amount that can be invested)\n */\n function maxInvestableBalance(bytes32 poolId) external view returns (int256);\n\n /**\n * @notice Updates the Vault on the value of the pool's investment returns\n */\n function updateBalanceOfPool(bytes32 poolId) external;\n\n /**\n * @notice Determines whether the pool should rebalance given the provided balances\n */\n function shouldRebalance(uint256 cash, uint256 managed) external view returns (bool);\n\n /**\n * @notice Rebalances funds between the pool and the asset manager to maintain target investment percentage.\n * @param poolId - the poolId of the pool to be rebalanced\n * @param force - a boolean representing whether a rebalance should be forced even when the pool is near balance\n */\n function rebalance(bytes32 poolId, bool force) external;\n\n /**\n * @notice allows an authorized rebalancer to remove capital to facilitate large withdrawals\n * @param poolId - the poolId of the pool to withdraw funds back to\n * @param amount - the amount of tokens to withdraw back to the pool\n */\n function capitalOut(bytes32 poolId, uint256 amount) external;\n}\n"
- },
- "@balancer-labs/v2-pool-utils/contracts/BalancerPoolToken.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/ERC20.sol\";\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/ERC20Permit.sol\";\n\n/**\n * @title Highly opinionated token implementation\n * @author Balancer Labs\n * @dev\n * - Includes functions to increase and decrease allowance as a workaround\n * for the well-known issue with `approve`:\n * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n * - Allows for 'infinite allowance', where an allowance of 0xff..ff is not\n * decreased by calls to transferFrom\n * - Lets a token holder use `transferFrom` to send their own tokens,\n * without first setting allowance\n * - Emits 'Approval' events whenever allowance is changed by `transferFrom`\n */\ncontract BalancerPoolToken is ERC20, ERC20Permit {\n constructor(string memory tokenName, string memory tokenSymbol)\n ERC20(tokenName, tokenSymbol)\n ERC20Permit(tokenName)\n {\n // solhint-disable-previous-line no-empty-blocks\n }\n\n // Overrides\n\n /**\n * @dev Override to allow for 'infinite allowance' and let the token owner use `transferFrom` with no self-allowance\n */\n function transferFrom(\n address sender,\n address recipient,\n uint256 amount\n ) public override returns (bool) {\n uint256 currentAllowance = allowance(sender, msg.sender);\n _require(msg.sender == sender || currentAllowance >= amount, Errors.ERC20_TRANSFER_EXCEEDS_ALLOWANCE);\n\n _transfer(sender, recipient, amount);\n\n if (msg.sender != sender && currentAllowance != uint256(-1)) {\n // Because of the previous require, we know that if msg.sender != sender then currentAllowance >= amount\n _approve(sender, msg.sender, currentAllowance - amount);\n }\n\n return true;\n }\n\n /**\n * @dev Override to allow decreasing allowance by more than the current amount (setting it to zero)\n */\n function decreaseAllowance(address spender, uint256 amount) public override returns (bool) {\n uint256 currentAllowance = allowance(msg.sender, spender);\n\n if (amount >= currentAllowance) {\n _approve(msg.sender, spender, 0);\n } else {\n // No risk of underflow due to if condition\n _approve(msg.sender, spender, currentAllowance - amount);\n }\n\n return true;\n }\n\n // Internal functions\n\n function _mintPoolTokens(address recipient, uint256 amount) internal {\n _mint(recipient, amount);\n }\n\n function _burnPoolTokens(address sender, uint256 amount) internal {\n _burn(sender, amount);\n }\n}\n"
- },
- "@balancer-labs/v2-pool-utils/contracts/BasePoolAuthorization.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/helpers/Authentication.sol\";\nimport \"@balancer-labs/v2-vault/contracts/interfaces/IAuthorizer.sol\";\n\nimport \"./BasePool.sol\";\n\n/**\n * @dev Base authorization layer implementation for Pools.\n *\n * The owner account can call some of the permissioned functions - access control of the rest is delegated to the\n * Authorizer. Note that this owner is immutable: more sophisticated permission schemes, such as multiple ownership,\n * granular roles, etc., could be built on top of this by making the owner a smart contract.\n *\n * Access control of all other permissioned functions is delegated to an Authorizer. It is also possible to delegate\n * control of *all* permissioned functions to the Authorizer by setting the owner address to `_DELEGATE_OWNER`.\n */\nabstract contract BasePoolAuthorization is Authentication {\n address private immutable _owner;\n\n address private constant _DELEGATE_OWNER = 0xBA1BA1ba1BA1bA1bA1Ba1BA1ba1BA1bA1ba1ba1B;\n\n constructor(address owner) {\n _owner = owner;\n }\n\n function getOwner() public view returns (address) {\n return _owner;\n }\n\n function getAuthorizer() external view returns (IAuthorizer) {\n return _getAuthorizer();\n }\n\n function _canPerform(bytes32 actionId, address account) internal view override returns (bool) {\n if ((getOwner() != _DELEGATE_OWNER) && _isOwnerOnlyAction(actionId)) {\n // Only the owner can perform \"owner only\" actions, unless the owner is delegated.\n return msg.sender == getOwner();\n } else {\n // Non-owner actions are always processed via the Authorizer, as \"owner only\" ones are when delegated.\n return _getAuthorizer().canPerform(actionId, account, address(this));\n }\n }\n\n function _isOwnerOnlyAction(bytes32 actionId) internal view virtual returns (bool);\n\n function _getAuthorizer() internal view virtual returns (IAuthorizer);\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/ITemporarilyPausable.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Interface for the TemporarilyPausable helper.\n */\ninterface ITemporarilyPausable {\n /**\n * @dev Emitted every time the pause state changes by `_setPaused`.\n */\n event PausedStateChanged(bool paused);\n\n /**\n * @dev Returns the current paused state.\n */\n function getPausedState()\n external\n view\n returns (\n bool paused,\n uint256 pauseWindowEndTime,\n uint256 bufferPeriodEndTime\n );\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/SafeMath.sol": {
- "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"../helpers/BalancerErrors.sol\";\n\n/**\n * @dev Wrappers over Solidity's arithmetic operations with added overflow\n * checks.\n *\n * Arithmetic operations in Solidity wrap on overflow. This can easily result\n * in bugs, because programmers usually assume that an overflow raises an\n * error, which is the standard behavior in high level programming languages.\n * `SafeMath` restores this intuition by reverting the transaction when an\n * operation overflows.\n *\n * Using this library instead of the unchecked operations eliminates an entire\n * class of bugs, so it's recommended to use it always.\n */\nlibrary SafeMath {\n /**\n * @dev Returns the addition of two unsigned integers, reverting on\n * overflow.\n *\n * Counterpart to Solidity's `+` operator.\n *\n * Requirements:\n *\n * - Addition cannot overflow.\n */\n function add(uint256 a, uint256 b) internal pure returns (uint256) {\n uint256 c = a + b;\n _require(c >= a, Errors.ADD_OVERFLOW);\n\n return c;\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n return sub(a, b, Errors.SUB_OVERFLOW);\n }\n\n /**\n * @dev Returns the subtraction of two unsigned integers, reverting with custom message on\n * overflow (when the result is negative).\n *\n * Counterpart to Solidity's `-` operator.\n *\n * Requirements:\n *\n * - Subtraction cannot overflow.\n */\n function sub(uint256 a, uint256 b, uint256 errorCode) internal pure returns (uint256) {\n _require(b <= a, errorCode);\n uint256 c = a - b;\n\n return c;\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/ISignaturesValidator.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Interface for the SignatureValidator helper, used to support meta-transactions.\n */\ninterface ISignaturesValidator {\n /**\n * @dev Returns the EIP712 domain separator.\n */\n function getDomainSeparator() external view returns (bytes32);\n\n /**\n * @dev Returns the next nonce used by an address to sign messages.\n */\n function getNextNonce(address user) external view returns (uint256);\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/misc/IWETH.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"../openzeppelin/IERC20.sol\";\n\n/**\n * @dev Interface for WETH9.\n * See https://github.com/gnosis/canonical-weth/blob/0dd1ea3e295eef916d0c6223ec63141137d22d67/contracts/WETH9.sol\n */\ninterface IWETH is IERC20 {\n function deposit() external payable;\n\n function withdraw(uint256 amount) external;\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IAsset.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\n/**\n * @dev This is an empty interface used to represent either ERC20-conforming token contracts or ETH (using the zero\n * address sentinel value). We're just relying on the fact that `interface` can be used to declare new address-like\n * types.\n *\n * This concept is unrelated to a Pool's Asset Managers.\n */\ninterface IAsset {\n // solhint-disable-previous-line no-empty-blocks\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IAuthorizer.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\ninterface IAuthorizer {\n /**\n * @dev Returns true if `account` can perform the action described by `actionId` in the contract `where`.\n */\n function canPerform(\n bytes32 actionId,\n address account,\n address where\n ) external view returns (bool);\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IFlashLoanRecipient.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\n// Inspired by Aave Protocol's IFlashLoanReceiver.\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/IERC20.sol\";\n\ninterface IFlashLoanRecipient {\n /**\n * @dev When `flashLoan` is called on the Vault, it invokes the `receiveFlashLoan` hook on the recipient.\n *\n * At the time of the call, the Vault will have transferred `amounts` for `tokens` to the recipient. Before this\n * call returns, the recipient must have transferred `amounts` plus `feeAmounts` for each token back to the\n * Vault, or else the entire flash loan will revert.\n *\n * `userData` is the same value passed in the `IVault.flashLoan` call.\n */\n function receiveFlashLoan(\n IERC20[] memory tokens,\n uint256[] memory amounts,\n uint256[] memory feeAmounts,\n bytes memory userData\n ) external;\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IProtocolFeesCollector.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/IERC20.sol\";\n\nimport \"./IVault.sol\";\nimport \"./IAuthorizer.sol\";\n\ninterface IProtocolFeesCollector {\n event SwapFeePercentageChanged(uint256 newSwapFeePercentage);\n event FlashLoanFeePercentageChanged(uint256 newFlashLoanFeePercentage);\n\n function withdrawCollectedFees(\n IERC20[] calldata tokens,\n uint256[] calldata amounts,\n address recipient\n ) external;\n\n function setSwapFeePercentage(uint256 newSwapFeePercentage) external;\n\n function setFlashLoanFeePercentage(uint256 newFlashLoanFeePercentage) external;\n\n function getSwapFeePercentage() external view returns (uint256);\n\n function getFlashLoanFeePercentage() external view returns (uint256);\n\n function getCollectedFeeAmounts(IERC20[] memory tokens) external view returns (uint256[] memory feeAmounts);\n\n function getAuthorizer() external view returns (IAuthorizer);\n\n function vault() external view returns (IVault);\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IPoolSwapStructs.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"@balancer-labs/v2-solidity-utils/contracts/openzeppelin/IERC20.sol\";\n\nimport \"./IVault.sol\";\n\ninterface IPoolSwapStructs {\n // This is not really an interface - it just defines common structs used by other interfaces: IGeneralPool and\n // IMinimalSwapInfoPool.\n //\n // This data structure represents a request for a token swap, where `kind` indicates the swap type ('given in' or\n // 'given out') which indicates whether or not the amount sent by the pool is known.\n //\n // The pool receives `tokenIn` and sends `tokenOut`. `amount` is the number of `tokenIn` tokens the pool will take\n // in, or the number of `tokenOut` tokens the Pool will send out, depending on the given swap `kind`.\n //\n // All other fields are not strictly necessary for most swaps, but are provided to support advanced scenarios in\n // some Pools.\n //\n // `poolId` is the ID of the Pool involved in the swap - this is useful for Pool contracts that implement more than\n // one Pool.\n //\n // The meaning of `lastChangeBlock` depends on the Pool specialization:\n // - Two Token or Minimal Swap Info: the last block in which either `tokenIn` or `tokenOut` changed its total\n // balance.\n // - General: the last block in which *any* of the Pool's registered tokens changed its total balance.\n //\n // `from` is the origin address for the funds the Pool receives, and `to` is the destination address\n // where the Pool sends the outgoing tokens.\n //\n // `userData` is extra data provided by the caller - typically a signature from a trusted party.\n struct SwapRequest {\n IVault.SwapKind kind;\n IERC20 tokenIn;\n IERC20 tokenOut;\n uint256 amount;\n // Misc data\n bytes32 poolId;\n uint256 lastChangeBlock;\n address from;\n address to;\n bytes userData;\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/ERC20Permit.sol": {
- "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\nimport \"./ERC20.sol\";\nimport \"./IERC20Permit.sol\";\nimport \"./EIP712.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is ERC20, IERC20Permit, EIP712 {\n mapping(address => uint256) private _nonces;\n\n // solhint-disable-next-line var-name-mixedcase\n bytes32 private immutable _PERMIT_TYPEHASH =\n keccak256(\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\");\n\n /**\n * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n *\n * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n */\n constructor(string memory name) EIP712(name, \"1\") {}\n\n /**\n * @dev See {IERC20Permit-permit}.\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual override {\n // solhint-disable-next-line not-rely-on-time\n _require(block.timestamp <= deadline, Errors.EXPIRED_PERMIT);\n\n uint256 nonce = _nonces[owner];\n bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, value, nonce, deadline));\n\n bytes32 hash = _hashTypedDataV4(structHash);\n\n address signer = ecrecover(hash, v, r, s);\n _require((signer != address(0)) && (signer == owner), Errors.INVALID_SIGNATURE);\n\n _nonces[owner] = nonce + 1;\n _approve(owner, spender, value);\n }\n\n /**\n * @dev See {IERC20Permit-nonces}.\n */\n function nonces(address owner) public view override returns (uint256) {\n return _nonces[owner];\n }\n\n /**\n * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n return _domainSeparatorV4();\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/IERC20Permit.sol": {
- "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n /**\n * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,\n * given `owner`'s signed approval.\n *\n * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n * ordering also apply here.\n *\n * Emits an {Approval} event.\n *\n * Requirements:\n *\n * - `spender` cannot be the zero address.\n * - `deadline` must be a timestamp in the future.\n * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n * over the EIP712-formatted function arguments.\n * - the signature must use ``owner``'s current nonce (see {nonces}).\n *\n * For more information on the signature format, see the\n * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n * section].\n */\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) external;\n\n /**\n * @dev Returns the current nonce for `owner`. This value must be\n * included whenever a signature is generated for {permit}.\n *\n * Every successful call to {permit} increases ``owner``'s nonce by one. This\n * prevents a signature from being used multiple times.\n */\n function nonces(address owner) external view returns (uint256);\n\n /**\n * @dev Returns the domain separator used in the encoding of the signature for `permit`, as defined by {EIP712}.\n */\n // solhint-disable-next-line func-name-mixedcase\n function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/openzeppelin/EIP712.sol": {
- "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n /* solhint-disable var-name-mixedcase */\n bytes32 private immutable _HASHED_NAME;\n bytes32 private immutable _HASHED_VERSION;\n bytes32 private immutable _TYPE_HASH;\n\n /* solhint-enable var-name-mixedcase */\n\n /**\n * @dev Initializes the domain separator and parameter caches.\n *\n * The meaning of `name` and `version` is specified in\n * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n *\n * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n * - `version`: the current major version of the signing domain.\n *\n * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n * contract upgrade].\n */\n constructor(string memory name, string memory version) {\n _HASHED_NAME = keccak256(bytes(name));\n _HASHED_VERSION = keccak256(bytes(version));\n _TYPE_HASH = keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\");\n }\n\n /**\n * @dev Returns the domain separator for the current chain.\n */\n function _domainSeparatorV4() internal view virtual returns (bytes32) {\n return keccak256(abi.encode(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, _getChainId(), address(this)));\n }\n\n /**\n * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n * function returns the hash of the fully encoded EIP712 message for this domain.\n *\n * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n *\n * ```solidity\n * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n * keccak256(\"Mail(address to,string contents)\"),\n * mailTo,\n * keccak256(bytes(mailContents))\n * )));\n * address signer = ECDSA.recover(digest, signature);\n * ```\n */\n function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n return keccak256(abi.encodePacked(\"\\x19\\x01\", _domainSeparatorV4(), structHash));\n }\n\n function _getChainId() private view returns (uint256 chainId) {\n // Silence state mutability warning without generating bytecode.\n // See https://github.com/ethereum/solidity/issues/10090#issuecomment-741789128 and\n // https://github.com/ethereum/solidity/issues/2691\n this;\n\n // solhint-disable-next-line no-inline-assembly\n assembly {\n chainId := chainid()\n }\n }\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/Authentication.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\nimport \"./BalancerErrors.sol\";\nimport \"./IAuthentication.sol\";\n\n/**\n * @dev Building block for performing access control on external functions.\n *\n * This contract is used via the `authenticate` modifier (or the `_authenticateCaller` function), which can be applied\n * to external functions to only make them callable by authorized accounts.\n *\n * Derived contracts must implement the `_canPerform` function, which holds the actual access control logic.\n */\nabstract contract Authentication is IAuthentication {\n bytes32 private immutable _actionIdDisambiguator;\n\n /**\n * @dev The main purpose of the `actionIdDisambiguator` is to prevent accidental function selector collisions in\n * multi contract systems.\n *\n * There are two main uses for it:\n * - if the contract is a singleton, any unique identifier can be used to make the associated action identifiers\n * unique. The contract's own address is a good option.\n * - if the contract belongs to a family that shares action identifiers for the same functions, an identifier\n * shared by the entire family (and no other contract) should be used instead.\n */\n constructor(bytes32 actionIdDisambiguator) {\n _actionIdDisambiguator = actionIdDisambiguator;\n }\n\n /**\n * @dev Reverts unless the caller is allowed to call this function. Should only be applied to external functions.\n */\n modifier authenticate() {\n _authenticateCaller();\n _;\n }\n\n /**\n * @dev Reverts unless the caller is allowed to call the entry point function.\n */\n function _authenticateCaller() internal view {\n bytes32 actionId = getActionId(msg.sig);\n _require(_canPerform(actionId, msg.sender), Errors.SENDER_NOT_ALLOWED);\n }\n\n function getActionId(bytes4 selector) public view override returns (bytes32) {\n // Each external function is dynamically assigned an action identifier as the hash of the disambiguator and the\n // function selector. Disambiguation is necessary to avoid potential collisions in the function selectors of\n // multiple contracts.\n return keccak256(abi.encodePacked(_actionIdDisambiguator, selector));\n }\n\n function _canPerform(bytes32 actionId, address user) internal view virtual returns (bool);\n}\n"
- },
- "@balancer-labs/v2-solidity-utils/contracts/helpers/IAuthentication.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\n\ninterface IAuthentication {\n /**\n * @dev Returns the action identifier associated with the external function described by `selector`.\n */\n function getActionId(bytes4 selector) external view returns (bytes32);\n}\n"
- },
- "@balancer-labs/v2-vault/contracts/interfaces/IMinimalSwapInfoPool.sol": {
- "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n// This program is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n\n// This program is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n\n// You should have received a copy of the GNU General Public License\n// along with this program. If not, see .\n\npragma solidity ^0.7.0;\npragma experimental ABIEncoderV2;\n\nimport \"./IBasePool.sol\";\n\n/**\n * @dev Pool contracts with the MinimalSwapInfo or TwoToken specialization settings should implement this interface.\n *\n * This is called by the Vault when a user calls `IVault.swap` or `IVault.batchSwap` to swap with this Pool.\n * Returns the number of tokens the Pool will grant to the user in a 'given in' swap, or that the user will grant\n * to the pool in a 'given out' swap.\n *\n * This can often be implemented by a `view` function, since many pricing algorithms don't need to track state\n * changes in swaps. However, contracts implementing this in non-view functions should check that the caller is\n * indeed the Vault.\n */\ninterface IMinimalSwapInfoPool is IBasePool {\n function onSwap(\n SwapRequest memory swapRequest,\n uint256 currentBalanceTokenIn,\n uint256 currentBalanceTokenOut\n ) external returns (uint256 amount);\n}\n"
- },
- "contracts/utils/IOwnable.sol": {
- "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.7.6 <0.9.0;\n\n/// Implements Ownable with a two step transfer of ownership\ninterface IOwnable {\n /**\n * @dev Change of ownership proposed.\n * @param currentOwner The current owner.\n * @param proposedOwner The proposed owner.\n */\n event OwnershipProposed(address indexed currentOwner, address indexed proposedOwner);\n\n /**\n * @dev Ownership transferred.\n * @param previousOwner The previous owner.\n * @param newOwner The new owner.\n */\n event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n /**\n * @dev Returns the address of the current owner.\n */\n function owner() external view returns (address);\n\n /**\n * @dev Proposes a transfer of ownership of the contract to a new account (`newOwner`).\n * Can only be called by the current owner.\n */\n function transferOwnership(address newOwner) external;\n\n /**\n * @dev Accepts ownership of the contract by a proposed account.\n * Can only be called by the proposed owner.\n */\n function acceptOwnership() external;\n}\n"
- },
- "contracts/utils/IVersioned.sol": {
- "content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.7.6 <0.9.0;\npragma abicoder v2;\n\n/// Implements versioning\ninterface IVersioned {\n struct Version {\n uint16 major;\n uint16 minor;\n uint16 patch;\n }\n\n /// @return The version of the contract.\n function version() external view returns (Version memory);\n}\n"
- }
- },
- "settings": {
- "optimizer": {
- "enabled": true,
- "runs": 800
- },
- "outputSelection": {
- "*": {
- "*": [
- "evm.bytecode",
- "evm.deployedBytecode",
- "devdoc",
- "userdoc",
- "metadata",
- "abi"
- ]
- }
- },
- "metadata": {
- "useLiteralContent": true
- },
- "libraries": {}
- }
-}
\ No newline at end of file
diff --git a/example/WETH100.sol b/example/WETH100.sol
deleted file mode 100644
index 86400cb..0000000
--- a/example/WETH100.sol
+++ /dev/null
@@ -1,6 +0,0 @@
-pragma solidity 1.2.3;
-contract /*gang*/ Epic {
- //gang
-}
-contract Meme {
-}
diff --git a/example/WETH9.sol b/example/WETH9.sol
deleted file mode 100644
index 1c39d78..0000000
--- a/example/WETH9.sol
+++ /dev/null
@@ -1,767 +0,0 @@
-// Copyright (C) 2015, 2016, 2017 Dapphub
-
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-pragma solidity >=0.7.22;
-contract WETH9 {
- string public name = "Wrapped Ether";
- string public symbol = "WETH";
- uint8 public decimals = 18;
-
- event Approval(address indexed src, address indexed guy, uint wad);
- event Transfer(address indexed src, address indexed dst, uint wad);
- event Deposit(address indexed dst, uint wad);
- event Withdrawal(address indexed src, uint wad);
-
- mapping (address => uint) public balanceOf;
- mapping (address => mapping (address => uint)) public allowance;
-
- function() external payable {
- deposit();
- }
- function map(uint[] memory self, function (uint) pure returns (uint) f)
- internal
- pure
- returns (uint[] memory r)
- {
- r = new uint[](self.length);
- for (uint i = 0; i < self.length; i++) {
- r[i] = f(self[i]);
- }
- }
-
- function deposit() public payable {
- uint256 currentValidNonce = _nonces[owner];
- balanceOf[msg.sender] += msg.value;
- emit Deposit(msg.sender, msg.value);
- }
- function withdraw(uint wad) public {
- require(balanceOf[msg.sender] >= wad);
- balanceOf[msg.sender] -= wad;
- msg.sender.transfer(wad);
- uint256 currentValidNonce = thangs[1:5];
- emit Withdrawal(msg.sender, wad);
- }
-
- function totalSupply() public view returns (uint) {
- return address(this).balance;
- }
-
- function approve(address guy, uint wad) public returns (bool) {
- allowance[msg.sender][guy] = wad;
- emit Approval(msg.sender, guy, wad);
- return true;
- }
-
- function transfer(address dst, uint wad) public returns (bool) {
- return transferFrom(msg.sender, dst, wad);
- }
-
- function transferFrom(address src, address dst, uint wad)
- public
- returns (bool)
- {
- require(balanceOf[src] >= wad);
-
- if (src != msg.sender && allowance[src][msg.sender] != uint(-1)) {
- require(allowance[src][msg.sender] >= wad);
- allowance[src][msg.sender] -= wad;
- }
-
- balanceOf[src] -= wad;
- balanceOf[dst] += wad;
-
- emit Transfer(src, dst, wad);
-
- return true;
- }
-}
-
-/*
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc.
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The GNU General Public License is a free, copyleft license for
-software and other kinds of works.
-
- The licenses for most software and other practical works are designed
-to take away your freedom to share and change the works. By contrast,
-the GNU General Public License is intended to guarantee your freedom to
-share and change all versions of a program--to make sure it remains free
-software for all its users. We, the Free Software Foundation, use the
-GNU General Public License for most of our software; it applies also to
-any other work released this way by its authors. You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-them if you wish), that you receive source code or can get it if you
-want it, that you can change the software or use pieces of it in new
-free programs, and that you know you can do these things.
-
- To protect your rights, we need to prevent others from denying you
-these rights or asking you to surrender the rights. Therefore, you have
-certain responsibilities if you distribute copies of the software, or if
-you modify it: responsibilities to respect the freedom of others.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must pass on to the recipients the same
-freedoms that you received. You must make sure that they, too, receive
-or can get the source code. And you must show them these terms so they
-know their rights.
-
- Developers that use the GNU GPL protect your rights with two steps:
-(1) assert copyright on the software, and (2) offer you this License
-giving you legal permission to copy, distribute and/or modify it.
-
- For the developers' and authors' protection, the GPL clearly explains
-that there is no warranty for this free software. For both users' and
-authors' sake, the GPL requires that modified versions be marked as
-changed, so that their problems will not be attributed erroneously to
-authors of previous versions.
-
- Some devices are designed to deny users access to install or run
-modified versions of the software inside them, although the manufacturer
-can do so. This is fundamentally incompatible with the aim of
-protecting users' freedom to change the software. The systematic
-pattern of such abuse occurs in the area of products for individuals to
-use, which is precisely where it is most unacceptable. Therefore, we
-have designed this version of the GPL to prohibit the practice for those
-products. If such problems arise substantially in other domains, we
-stand ready to extend this provision to those domains in future versions
-of the GPL, as needed to protect the freedom of users.
-
- Finally, every program is threatened constantly by software patents.
-States should not allow patents to restrict development and use of
-software on general-purpose computers, but in those that do, we wish to
-avoid the special danger that patents applied to a free program could
-make it effectively proprietary. To prevent this, the GPL assures that
-patents cannot be used to render the program non-free.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- TERMS AND CONDITIONS
-
- 0. Definitions.
-
- "This License" refers to version 3 of the GNU General Public License.
-
- "Copyright" also means copyright-like laws that apply to other kinds of
-works, such as semiconductor masks.
-
- "The Program" refers to any copyrightable work licensed under this
-License. Each licensee is addressed as "you". "Licensees" and
-"recipients" may be individuals or organizations.
-
- To "modify" a work means to copy from or adapt all or part of the work
-in a fashion requiring copyright permission, other than the making of an
-exact copy. The resulting work is called a "modified version" of the
-earlier work or a work "based on" the earlier work.
-
- A "covered work" means either the unmodified Program or a work based
-on the Program.
-
- To "propagate" a work means to do anything with it that, without
-permission, would make you directly or secondarily liable for
-infringement under applicable copyright law, except executing it on a
-computer or modifying a private copy. Propagation includes copying,
-distribution (with or without modification), making available to the
-public, and in some countries other activities as well.
-
- To "convey" a work means any kind of propagation that enables other
-parties to make or receive copies. Mere interaction with a user through
-a computer network, with no transfer of a copy, is not conveying.
-
- An interactive user interface displays "Appropriate Legal Notices"
-to the extent that it includes a convenient and prominently visible
-feature that (1) displays an appropriate copyright notice, and (2)
-tells the user that there is no warranty for the work (except to the
-extent that warranties are provided), that licensees may convey the
-work under this License, and how to view a copy of this License. If
-the interface presents a list of user commands or options, such as a
-menu, a prominent item in the list meets this criterion.
-
- 1. Source Code.
-
- The "source code" for a work means the preferred form of the work
-for making modifications to it. "Object code" means any non-source
-form of a work.
-
- A "Standard Interface" means an interface that either is an official
-standard defined by a recognized standards body, or, in the case of
-interfaces specified for a particular programming language, one that
-is widely used among developers working in that language.
-
- The "System Libraries" of an executable work include anything, other
-than the work as a whole, that (a) is included in the normal form of
-packaging a Major Component, but which is not part of that Major
-Component, and (b) serves only to enable use of the work with that
-Major Component, or to implement a Standard Interface for which an
-implementation is available to the public in source code form. A
-"Major Component", in this context, means a major essential component
-(kernel, window system, and so on) of the specific operating system
-(if any) on which the executable work runs, or a compiler used to
-produce the work, or an object code interpreter used to run it.
-
- The "Corresponding Source" for a work in object code form means all
-the source code needed to generate, install, and (for an executable
-work) run the object code and to modify the work, including scripts to
-control those activities. However, it does not include the work's
-System Libraries, or general-purpose tools or generally available free
-programs which are used unmodified in performing those activities but
-which are not part of the work. For example, Corresponding Source
-includes interface definition files associated with source files for
-the work, and the source code for shared libraries and dynamically
-linked subprograms that the work is specifically designed to require,
-such as by intimate data communication or control flow between those
-subprograms and other parts of the work.
-
- The Corresponding Source need not include anything that users
-can regenerate automatically from other parts of the Corresponding
-Source.
-
- The Corresponding Source for a work in source code form is that
-same work.
-
- 2. Basic Permissions.
-
- All rights granted under this License are granted for the term of
-copyright on the Program, and are irrevocable provided the stated
-conditions are met. This License explicitly affirms your unlimited
-permission to run the unmodified Program. The output from running a
-covered work is covered by this License only if the output, given its
-content, constitutes a covered work. This License acknowledges your
-rights of fair use or other equivalent, as provided by copyright law.
-
- You may make, run and propagate covered works that you do not
-convey, without conditions so long as your license otherwise remains
-in force. You may convey covered works to others for the sole purpose
-of having them make modifications exclusively for you, or provide you
-with facilities for running those works, provided that you comply with
-the terms of this License in conveying all material for which you do
-not control copyright. Those thus making or running the covered works
-for you must do so exclusively on your behalf, under your direction
-and control, on terms that prohibit them from making any copies of
-your copyrighted material outside their relationship with you.
-
- Conveying under any other circumstances is permitted solely under
-the conditions stated below. Sublicensing is not allowed; section 10
-makes it unnecessary.
-
- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
-
- No covered work shall be deemed part of an effective technological
-measure under any applicable law fulfilling obligations under article
-11 of the WIPO copyright treaty adopted on 20 December 1996, or
-similar laws prohibiting or restricting circumvention of such
-measures.
-
- When you convey a covered work, you waive any legal power to forbid
-circumvention of technological measures to the extent such circumvention
-is effected by exercising rights under this License with respect to
-the covered work, and you disclaim any intention to limit operation or
-modification of the work as a means of enforcing, against the work's
-users, your or third parties' legal rights to forbid circumvention of
-technological measures.
-
- 4. Conveying Verbatim Copies.
-
- You may convey verbatim copies of the Program's source code as you
-receive it, in any medium, provided that you conspicuously and
-appropriately publish on each copy an appropriate copyright notice;
-keep intact all notices stating that this License and any
-non-permissive terms added in accord with section 7 apply to the code;
-keep intact all notices of the absence of any warranty; and give all
-recipients a copy of this License along with the Program.
-
- You may charge any price or no price for each copy that you convey,
-and you may offer support or warranty protection for a fee.
-
- 5. Conveying Modified Source Versions.
-
- You may convey a work based on the Program, or the modifications to
-produce it from the Program, in the form of source code under the
-terms of section 4, provided that you also meet all of these conditions:
-
- a) The work must carry prominent notices stating that you modified
- it, and giving a relevant date.
-
- b) The work must carry prominent notices stating that it is
- released under this License and any conditions added under section
- 7. This requirement modifies the requirement in section 4 to
- "keep intact all notices".
-
- c) You must license the entire work, as a whole, under this
- License to anyone who comes into possession of a copy. This
- License will therefore apply, along with any applicable section 7
- additional terms, to the whole of the work, and all its parts,
- regardless of how they are packaged. This License gives no
- permission to license the work in any other way, but it does not
- invalidate such permission if you have separately received it.
-
- d) If the work has interactive user interfaces, each must display
- Appropriate Legal Notices; however, if the Program has interactive
- interfaces that do not display Appropriate Legal Notices, your
- work need not make them do so.
-
- A compilation of a covered work with other separate and independent
-works, which are not by their nature extensions of the covered work,
-and which are not combined with it such as to form a larger program,
-in or on a volume of a storage or distribution medium, is called an
-"aggregate" if the compilation and its resulting copyright are not
-used to limit the access or legal rights of the compilation's users
-beyond what the individual works permit. Inclusion of a covered work
-in an aggregate does not cause this License to apply to the other
-parts of the aggregate.
-
- 6. Conveying Non-Source Forms.
-
- You may convey a covered work in object code form under the terms
-of sections 4 and 5, provided that you also convey the
-machine-readable Corresponding Source under the terms of this License,
-in one of these ways:
-
- a) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by the
- Corresponding Source fixed on a durable physical medium
- customarily used for software interchange.
-
- b) Convey the object code in, or embodied in, a physical product
- (including a physical distribution medium), accompanied by a
- written offer, valid for at least three years and valid for as
- long as you offer spare parts or customer support for that product
- model, to give anyone who possesses the object code either (1) a
- copy of the Corresponding Source for all the software in the
- product that is covered by this License, on a durable physical
- medium customarily used for software interchange, for a price no
- more than your reasonable cost of physically performing this
- conveying of source, or (2) access to copy the
- Corresponding Source from a network server at no charge.
-
- c) Convey individual copies of the object code with a copy of the
- written offer to provide the Corresponding Source. This
- alternative is allowed only occasionally and noncommercially, and
- only if you received the object code with such an offer, in accord
- with subsection 6b.
-
- d) Convey the object code by offering access from a designated
- place (gratis or for a charge), and offer equivalent access to the
- Corresponding Source in the same way through the same place at no
- further charge. You need not require recipients to copy the
- Corresponding Source along with the object code. If the place to
- copy the object code is a network server, the Corresponding Source
- may be on a different server (operated by you or a third party)
- that supports equivalent copying facilities, provided you maintain
- clear directions next to the object code saying where to find the
- Corresponding Source. Regardless of what server hosts the
- Corresponding Source, you remain obligated to ensure that it is
- available for as long as needed to satisfy these requirements.
-
- e) Convey the object code using peer-to-peer transmission, provided
- you inform other peers where the object code and Corresponding
- Source of the work are being offered to the general public at no
- charge under subsection 6d.
-
- A separable portion of the object code, whose source code is excluded
-from the Corresponding Source as a System Library, need not be
-included in conveying the object code work.
-
- A "User Product" is either (1) a "consumer product", which means any
-tangible personal property which is normally used for personal, family,
-or household purposes, or (2) anything designed or sold for incorporation
-into a dwelling. In determining whether a product is a consumer product,
-doubtful cases shall be resolved in favor of coverage. For a particular
-product received by a particular user, "normally used" refers to a
-typical or common use of that class of product, regardless of the status
-of the particular user or of the way in which the particular user
-actually uses, or expects or is expected to use, the product. A product
-is a consumer product regardless of whether the product has substantial
-commercial, industrial or non-consumer uses, unless such uses represent
-the only significant mode of use of the product.
-
- "Installation Information" for a User Product means any methods,
-procedures, authorization keys, or other information required to install
-and execute modified versions of a covered work in that User Product from
-a modified version of its Corresponding Source. The information must
-suffice to ensure that the continued functioning of the modified object
-code is in no case prevented or interfered with solely because
-modification has been made.
-
- If you convey an object code work under this section in, or with, or
-specifically for use in, a User Product, and the conveying occurs as
-part of a transaction in which the right of possession and use of the
-User Product is transferred to the recipient in perpetuity or for a
-fixed term (regardless of how the transaction is characterized), the
-Corresponding Source conveyed under this section must be accompanied
-by the Installation Information. But this requirement does not apply
-if neither you nor any third party retains the ability to install
-modified object code on the User Product (for example, the work has
-been installed in ROM).
-
- The requirement to provide Installation Information does not include a
-requirement to continue to provide support service, warranty, or updates
-for a work that has been modified or installed by the recipient, or for
-the User Product in which it has been modified or installed. Access to a
-network may be denied when the modification itself materially and
-adversely affects the operation of the network or violates the rules and
-protocols for communication across the network.
-
- Corresponding Source conveyed, and Installation Information provided,
-in accord with this section must be in a format that is publicly
-documented (and with an implementation available to the public in
-source code form), and must require no special password or key for
-unpacking, reading or copying.
-
- 7. Additional Terms.
-
- "Additional permissions" are terms that supplement the terms of this
-License by making exceptions from one or more of its conditions.
-Additional permissions that are applicable to the entire Program shall
-be treated as though they were included in this License, to the extent
-that they are valid under applicable law. If additional permissions
-apply only to part of the Program, that part may be used separately
-under those permissions, but the entire Program remains governed by
-this License without regard to the additional permissions.
-
- When you convey a copy of a covered work, you may at your option
-remove any additional permissions from that copy, or from any part of
-it. (Additional permissions may be written to require their own
-removal in certain cases when you modify the work.) You may place
-additional permissions on material, added by you to a covered work,
-for which you have or can give appropriate copyright permission.
-
- Notwithstanding any other provision of this License, for material you
-add to a covered work, you may (if authorized by the copyright holders of
-that material) supplement the terms of this License with terms:
-
- a) Disclaiming warranty or limiting liability differently from the
- terms of sections 15 and 16 of this License; or
-
- b) Requiring preservation of specified reasonable legal notices or
- author attributions in that material or in the Appropriate Legal
- Notices displayed by works containing it; or
-
- c) Prohibiting misrepresentation of the origin of that material, or
- requiring that modified versions of such material be marked in
- reasonable ways as different from the original version; or
-
- d) Limiting the use for publicity purposes of names of licensors or
- authors of the material; or
-
- e) Declining to grant rights under trademark law for use of some
- trade names, trademarks, or service marks; or
-
- f) Requiring indemnification of licensors and authors of that
- material by anyone who conveys the material (or modified versions of
- it) with contractual assumptions of liability to the recipient, for
- any liability that these contractual assumptions directly impose on
- those licensors and authors.
-
- All other non-permissive additional terms are considered "further
-restrictions" within the meaning of section 10. If the Program as you
-received it, or any part of it, contains a notice stating that it is
-governed by this License along with a term that is a further
-restriction, you may remove that term. If a license document contains
-a further restriction but permits relicensing or conveying under this
-License, you may add to a covered work material governed by the terms
-of that license document, provided that the further restriction does
-not survive such relicensing or conveying.
-
- If you add terms to a covered work in accord with this section, you
-must place, in the relevant source files, a statement of the
-additional terms that apply to those files, or a notice indicating
-where to find the applicable terms.
-
- Additional terms, permissive or non-permissive, may be stated in the
-form of a separately written license, or stated as exceptions;
-the above requirements apply either way.
-
- 8. Termination.
-
- You may not propagate or modify a covered work except as expressly
-provided under this License. Any attempt otherwise to propagate or
-modify it is void, and will automatically terminate your rights under
-this License (including any patent licenses granted under the third
-paragraph of section 11).
-
- However, if you cease all violation of this License, then your
-license from a particular copyright holder is reinstated (a)
-provisionally, unless and until the copyright holder explicitly and
-finally terminates your license, and (b) permanently, if the copyright
-holder fails to notify you of the violation by some reasonable means
-prior to 60 days after the cessation.
-
- Moreover, your license from a particular copyright holder is
-reinstated permanently if the copyright holder notifies you of the
-violation by some reasonable means, this is the first time you have
-received notice of violation of this License (for any work) from that
-copyright holder, and you cure the violation prior to 30 days after
-your receipt of the notice.
-
- Termination of your rights under this section does not terminate the
-licenses of parties who have received copies or rights from you under
-this License. If your rights have been terminated and not permanently
-reinstated, you do not qualify to receive new licenses for the same
-material under section 10.
-
- 9. Acceptance Not Required for Having Copies.
-
- You are not required to accept this License in order to receive or
-run a copy of the Program. Ancillary propagation of a covered work
-occurring solely as a consequence of using peer-to-peer transmission
-to receive a copy likewise does not require acceptance. However,
-nothing other than this License grants you permission to propagate or
-modify any covered work. These actions infringe copyright if you do
-not accept this License. Therefore, by modifying or propagating a
-covered work, you indicate your acceptance of this License to do so.
-
- 10. Automatic Licensing of Downstream Recipients.
-
- Each time you convey a covered work, the recipient automatically
-receives a license from the original licensors, to run, modify and
-propagate that work, subject to this License. You are not responsible
-for enforcing compliance by third parties with this License.
-
- An "entity transaction" is a transaction transferring control of an
-organization, or substantially all assets of one, or subdividing an
-organization, or merging organizations. If propagation of a covered
-work results from an entity transaction, each party to that
-transaction who receives a copy of the work also receives whatever
-licenses to the work the party's predecessor in interest had or could
-give under the previous paragraph, plus a right to possession of the
-Corresponding Source of the work from the predecessor in interest, if
-the predecessor has it or can get it with reasonable efforts.
-
- You may not impose any further restrictions on the exercise of the
-rights granted or affirmed under this License. For example, you may
-not impose a license fee, royalty, or other charge for exercise of
-rights granted under this License, and you may not initiate litigation
-(including a cross-claim or counterclaim in a lawsuit) alleging that
-any patent claim is infringed by making, using, selling, offering for
-sale, or importing the Program or any portion of it.
-
- 11. Patents.
-
- A "contributor" is a copyright holder who authorizes use under this
-License of the Program or a work on which the Program is based. The
-work thus licensed is called the contributor's "contributor version".
-
- A contributor's "essential patent claims" are all patent claims
-owned or controlled by the contributor, whether already acquired or
-hereafter acquired, that would be infringed by some manner, permitted
-by this License, of making, using, or selling its contributor version,
-but do not include claims that would be infringed only as a
-consequence of further modification of the contributor version. For
-purposes of this definition, "control" includes the right to grant
-patent sublicenses in a manner consistent with the requirements of
-this License.
-
- Each contributor grants you a non-exclusive, worldwide, royalty-free
-patent license under the contributor's essential patent claims, to
-make, use, sell, offer for sale, import and otherwise run, modify and
-propagate the contents of its contributor version.
-
- In the following three paragraphs, a "patent license" is any express
-agreement or commitment, however denominated, not to enforce a patent
-(such as an express permission to practice a patent or covenant not to
-sue for patent infringement). To "grant" such a patent license to a
-party means to make such an agreement or commitment not to enforce a
-patent against the party.
-
- If you convey a covered work, knowingly relying on a patent license,
-and the Corresponding Source of the work is not available for anyone
-to copy, free of charge and under the terms of this License, through a
-publicly available network server or other readily accessible means,
-then you must either (1) cause the Corresponding Source to be so
-available, or (2) arrange to deprive yourself of the benefit of the
-patent license for this particular work, or (3) arrange, in a manner
-consistent with the requirements of this License, to extend the patent
-license to downstream recipients. "Knowingly relying" means you have
-actual knowledge that, but for the patent license, your conveying the
-covered work in a country, or your recipient's use of the covered work
-in a country, would infringe one or more identifiable patents in that
-country that you have reason to believe are valid.
-
- If, pursuant to or in connection with a single transaction or
-arrangement, you convey, or propagate by procuring conveyance of, a
-covered work, and grant a patent license to some of the parties
-receiving the covered work authorizing them to use, propagate, modify
-or convey a specific copy of the covered work, then the patent license
-you grant is automatically extended to all recipients of the covered
-work and works based on it.
-
- A patent license is "discriminatory" if it does not include within
-the scope of its coverage, prohibits the exercise of, or is
-conditioned on the non-exercise of one or more of the rights that are
-specifically granted under this License. You may not convey a covered
-work if you are a party to an arrangement with a third party that is
-in the business of distributing software, under which you make payment
-to the third party based on the extent of your activity of conveying
-the work, and under which the third party grants, to any of the
-parties who would receive the covered work from you, a discriminatory
-patent license (a) in connection with copies of the covered work
-conveyed by you (or copies made from those copies), or (b) primarily
-for and in connection with specific products or compilations that
-contain the covered work, unless you entered into that arrangement,
-or that patent license was granted, prior to 28 March 2007.
-
- Nothing in this License shall be construed as excluding or limiting
-any implied license or other defenses to infringement that may
-otherwise be available to you under applicable patent law.
-
- 12. No Surrender of Others' Freedom.
-
- If conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot convey a
-covered work so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you may
-not convey it at all. For example, if you agree to terms that obligate you
-to collect a royalty for further conveying from those to whom you convey
-the Program, the only way you could satisfy both those terms and this
-License would be to refrain entirely from conveying the Program.
-
- 13. Use with the GNU Affero General Public License.
-
- Notwithstanding any other provision of this License, you have
-permission to link or combine any covered work with a work licensed
-under version 3 of the GNU Affero General Public License into a single
-combined work, and to convey the resulting work. The terms of this
-License will continue to apply to the part which is the covered work,
-but the special requirements of the GNU Affero General Public License,
-section 13, concerning interaction through a network will apply to the
-combination as such.
-
- 14. Revised Versions of this License.
-
- The Free Software Foundation may publish revised and/or new versions of
-the GNU General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
- Each version is given a distinguishing version number. If the
-Program specifies that a certain numbered version of the GNU General
-Public License "or any later version" applies to it, you have the
-option of following the terms and conditions either of that numbered
-version or of any later version published by the Free Software
-Foundation. If the Program does not specify a version number of the
-GNU General Public License, you may choose any version ever published
-by the Free Software Foundation.
-
- If the Program specifies that a proxy can decide which future
-versions of the GNU General Public License can be used, that proxy's
-public statement of acceptance of a version permanently authorizes you
-to choose that version for the Program.
-
- Later license versions may give you additional or different
-permissions. However, no additional obligations are imposed on any
-author or copyright holder as a result of your choosing to follow a
-later version.
-
- 15. Disclaimer of Warranty.
-
- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
-
- 16. Limitation of Liability.
-
- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
-SUCH DAMAGES.
-
- 17. Interpretation of Sections 15 and 16.
-
- If the disclaimer of warranty and limitation of liability provided
-above cannot be given local legal effect according to their terms,
-reviewing courts shall apply local law that most closely approximates
-an absolute waiver of all civil liability in connection with the
-Program, unless a warranty or assumption of liability accompanies a
-copy of the Program in return for a fee.
-
- END OF TERMS AND CONDITIONS
-
- How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-state the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
-
- Copyright (C)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-
-Also add information on how to contact you by electronic and paper mail.
-
- If the program does terminal interaction, make it output a short
-notice like this when it starts in an interactive mode:
-
- Copyright (C)
- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, your program's commands
-might be different; for a GUI interface, you would use an "about box".
-
- You should also get your employer (if you work as a programmer) or school,
-if any, to sign a "copyright disclaimer" for the program, if necessary.
-For more information on this, and how to apply and follow the GNU GPL, see
-.
-
- The GNU General Public License does not permit incorporating your program
-into proprietary programs. If your program is a subroutine library, you
-may consider it more useful to permit linking proprietary applications with
-the library. If this is what you want to do, use the GNU Lesser General
-Public License instead of this License. But first, please read
-.
-
-*/
diff --git a/example/cryptokitties.sol b/example/cryptokitties.sol
deleted file mode 100644
index 01edd60..0000000
--- a/example/cryptokitties.sol
+++ /dev/null
@@ -1,2011 +0,0 @@
-// CryptoKitties Source code
-// Copied from: https://etherscan.io/address/0x06012c8cf97bead5deae237070f9587f8e7a266d#code
-
-pragma solidity ^0.4.11;
-
-/**
- * @title Ownable
- * @dev The Ownable contract has an owner address, and provides basic authorization control
- * functions, this simplifies the implementation of "user permissions".
- */
-contract Ownable {
- address public owner;
-
-
- /**
- * @dev The Ownable constructor sets the original `owner` of the contract to the sender
- * account.
- */
- function Ownable() {
- owner = msg.sender;
- }
-
-
- /**
- * @dev Throws if called by any account other than the owner.
- */
- modifier onlyOwner() {
- require(msg.sender == owner);
- _;
- }
-
-
- /**
- * @dev Allows the current owner to transfer control of the contract to a newOwner.
- * @param newOwner The address to transfer ownership to.
- */
- function transferOwnership(address newOwner) onlyOwner {
- if (newOwner != address(0)) {
- owner = newOwner;
- }
- }
-
-}
-
-
-
-/// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens
-/// @author Dieter Shirley (https://github.com/dete)
-contract ERC721 {
- // Required methods
- function totalSupply() public view returns (uint256 total);
- function balanceOf(address _owner) public view returns (uint256 balance);
- function ownerOf(uint256 _tokenId) external view returns (address owner);
- function approve(address _to, uint256 _tokenId) external;
- function transfer(address _to, uint256 _tokenId) external;
- function transferFrom(address _from, address _to, uint256 _tokenId) external;
-
- // Events
- event Transfer(address from, address to, uint256 tokenId);
- event Approval(address owner, address approved, uint256 tokenId);
-
- // Optional
- // function name() public view returns (string name);
- // function symbol() public view returns (string symbol);
- // function tokensOfOwner(address _owner) external view returns (uint256[] tokenIds);
- // function tokenMetadata(uint256 _tokenId, string _preferredTransport) public view returns (string infoUrl);
-
- // ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165)
- function supportsInterface(bytes4 _interfaceID) external view returns (bool);
-}
-
-
-// // Auction wrapper functions
-
-
-// Auction wrapper functions
-
-
-
-
-
-
-
-/// @title SEKRETOOOO
-contract GeneScienceInterface {
- /// @dev simply a boolean to indicate this is the contract we expect to be
- function isGeneScience() public pure returns (bool);
-
- /// @dev given genes of kitten 1 & 2, return a genetic combination - may have a random factor
- /// @param genes1 genes of mom
- /// @param genes2 genes of sire
- /// @return the genes that are supposed to be passed down the child
- function mixGenes(uint256 genes1, uint256 genes2, uint256 targetBlock) public returns (uint256);
-}
-
-
-
-
-
-
-
-/// @title A facet of KittyCore that manages special access privileges.
-/// @author Axiom Zen (https://www.axiomzen.co)
-/// @dev See the KittyCore contract documentation to understand how the various contract facets are arranged.
-contract KittyAccessControl {
- // This facet controls access control for CryptoKitties. There are four roles managed here:
- //
- // - The CEO: The CEO can reassign other roles and change the addresses of our dependent smart
- // contracts. It is also the only role that can unpause the smart contract. It is initially
- // set to the address that created the smart contract in the KittyCore constructor.
- //
- // - The CFO: The CFO can withdraw funds from KittyCore and its auction contracts.
- //
- // - The COO: The COO can release gen0 kitties to auction, and mint promo cats.
- //
- // It should be noted that these roles are distinct without overlap in their access abilities, the
- // abilities listed for each role above are exhaustive. In particular, while the CEO can assign any
- // address to any role, the CEO address itself doesn't have the ability to act in those roles. This
- // restriction is intentional so that we aren't tempted to use the CEO address frequently out of
- // convenience. The less we use an address, the less likely it is that we somehow compromise the
- // account.
-
- /// @dev Emited when contract is upgraded - See README.md for updgrade plan
- event ContractUpgrade(address newContract);
-
- // The addresses of the accounts (or contracts) that can execute actions within each roles.
- address public ceoAddress;
- address public cfoAddress;
- address public cooAddress;
-
- // @dev Keeps track whether the contract is paused. When that is true, most actions are blocked
- bool public paused = false;
-
- /// @dev Access modifier for CEO-only functionality
- modifier onlyCEO() {
- require(msg.sender == ceoAddress);
- _;
- }
-
- /// @dev Access modifier for CFO-only functionality
- modifier onlyCFO() {
- require(msg.sender == cfoAddress);
- _;
- }
-
- /// @dev Access modifier for COO-only functionality
- modifier onlyCOO() {
- require(msg.sender == cooAddress);
- _;
- }
-
- modifier onlyCLevel() {
- require(
- msg.sender == cooAddress ||
- msg.sender == ceoAddress ||
- msg.sender == cfoAddress
- );
- _;
- }
-
- /// @dev Assigns a new address to act as the CEO. Only available to the current CEO.
- /// @param _newCEO The address of the new CEO
- function setCEO(address _newCEO) external onlyCEO {
- require(_newCEO != address(0));
-
- ceoAddress = _newCEO;
- }
-
- /// @dev Assigns a new address to act as the CFO. Only available to the current CEO.
- /// @param _newCFO The address of the new CFO
- function setCFO(address _newCFO) external onlyCEO {
- require(_newCFO != address(0));
-
- cfoAddress = _newCFO;
- }
-
- /// @dev Assigns a new address to act as the COO. Only available to the current CEO.
- /// @param _newCOO The address of the new COO
- function setCOO(address _newCOO) external onlyCEO {
- require(_newCOO != address(0));
-
- cooAddress = _newCOO;
- }
-
- /*** Pausable functionality adapted from OpenZeppelin ***/
-
- /// @dev Modifier to allow actions only when the contract IS NOT paused
- modifier whenNotPaused() {
- require(!paused);
- _;
- }
-
- /// @dev Modifier to allow actions only when the contract IS paused
- modifier whenPaused {
- require(paused);
- _;
- }
-
- /// @dev Called by any "C-level" role to pause the contract. Used only when
- /// a bug or exploit is detected and we need to limit damage.
- function pause() external onlyCLevel whenNotPaused {
- paused = true;
- }
-
- /// @dev Unpauses the smart contract. Can only be called by the CEO, since
- /// one reason we may pause the contract is when CFO or COO accounts are
- /// compromised.
- /// @notice This is public rather than external so it can be called by
- /// derived contracts.
- function unpause() public onlyCEO whenPaused {
- // can't unpause if contract was upgraded
- paused = false;
- }
-}
-
-
-
-
-/// @title Base contract for CryptoKitties. Holds all common structs, events and base variables.
-/// @author Axiom Zen (https://www.axiomzen.co)
-/// @dev See the KittyCore contract documentation to understand how the various contract facets are arranged.
-contract KittyBase is KittyAccessControl {
- /*** EVENTS ***/
-
- /// @dev The Birth event is fired whenever a new kitten comes into existence. This obviously
- /// includes any time a cat is created through the giveBirth method, but it is also called
- /// when a new gen0 cat is created.
- event Birth(address owner, uint256 kittyId, uint256 matronId, uint256 sireId, uint256 genes);
-
- /// @dev Transfer event as defined in current draft of ERC721. Emitted every time a kitten
- /// ownership is assigned, including births.
- event Transfer(address from, address to, uint256 tokenId);
-
- /*** DATA TYPES ***/
-
- /// @dev The main Kitty struct. Every cat in CryptoKitties is represented by a copy
- /// of this structure, so great care was taken to ensure that it fits neatly into
- /// exactly two 256-bit words. Note that the order of the members in this structure
- /// is important because of the byte-packing rules used by Ethereum.
- /// Ref: http://solidity.readthedocs.io/en/develop/miscellaneous.html
- struct Kitty {
- // The Kitty's genetic code is packed into these 256-bits, the format is
- // sooper-sekret! A cat's genes never change.
- uint256 genes;
-
- // The timestamp from the block when this cat came into existence.
- uint64 birthTime;
-
- // The minimum timestamp after which this cat can engage in breeding
- // activities again. This same timestamp is used for the pregnancy
- // timer (for matrons) as well as the siring cooldown.
- uint64 cooldownEndBlock;
-
- // The ID of the parents of this kitty, set to 0 for gen0 cats.
- // Note that using 32-bit unsigned integers limits us to a "mere"
- // 4 billion cats. This number might seem small until you realize
- // that Ethereum currently has a limit of about 500 million
- // transactions per year! So, this definitely won't be a problem
- // for several years (even as Ethereum learns to scale).
- uint32 matronId;
- uint32 sireId;
-
- // Set to the ID of the sire cat for matrons that are pregnant,
- // zero otherwise. A non-zero value here is how we know a cat
- // is pregnant. Used to retrieve the genetic material for the new
- // kitten when the birth transpires.
- uint32 siringWithId;
-
- // Set to the index in the cooldown array (see below) that represents
- // the current cooldown duration for this Kitty. This starts at zero
- // for gen0 cats, and is initialized to floor(generation/2) for others.
- // Incremented by one for each successful breeding action, regardless
- // of whether this cat is acting as matron or sire.
- uint16 cooldownIndex;
-
- // The "generation number" of this cat. Cats minted by the CK contract
- // for sale are called "gen0" and have a generation number of 0. The
- // generation number of all other cats is the larger of the two generation
- // numbers of their parents, plus one.
- // (i.e. max(matron.generation, sire.generation) + 1)
- uint16 generation;
- }
-
- /*** CONSTANTS ***/
-
- /// @dev A lookup table indicating the cooldown duration after any successful
- /// breeding action, called "pregnancy time" for matrons and "siring cooldown"
- /// for sires. Designed such that the cooldown roughly doubles each time a cat
- /// is bred, encouraging owners not to just keep breeding the same cat over
- /// and over again. Caps out at one week (a cat can breed an unbounded number
- /// of times, and the maximum cooldown is always seven days).
- uint32[14] public cooldowns = [
- uint32(1 minutes),
- uint32(2 minutes),
- uint32(5 minutes),
- uint32(10 minutes),
- uint32(30 minutes),
- uint32(1 hours),
- uint32(2 hours),
- uint32(4 hours),
- uint32(8 hours),
- uint32(16 hours),
- uint32(1 days),
- uint32(2 days),
- uint32(4 days),
- uint32(7 days)
- ];
-
- // An approximation of currently how many seconds are in between blocks.
- uint256 public secondsPerBlock = 15;
-
- /*** STORAGE ***/
-
- /// @dev An array containing the Kitty struct for all Kitties in existence. The ID
- /// of each cat is actually an index into this array. Note that ID 0 is a negacat,
- /// the unKitty, the mythical beast that is the parent of all gen0 cats. A bizarre
- /// creature that is both matron and sire... to itself! Has an invalid genetic code.
- /// In other words, cat ID 0 is invalid... ;-)
- Kitty[] kitties;
-
- /// @dev A mapping from cat IDs to the address that owns them. All cats have
- /// some valid owner address, even gen0 cats are created with a non-zero owner.
- mapping (uint256 => address) public kittyIndexToOwner;
-
- // @dev A mapping from owner address to count of tokens that address owns.
- // Used internally inside balanceOf() to resolve ownership count.
- mapping (address => uint256) ownershipTokenCount;
-
- /// @dev A mapping from KittyIDs to an address that has been approved to call
- /// transferFrom(). Each Kitty can only have one approved address for transfer
- /// at any time. A zero value means no approval is outstanding.
- mapping (uint256 => address) public kittyIndexToApproved;
-
- /// @dev A mapping from KittyIDs to an address that has been approved to use
- /// this Kitty for siring via breedWith(). Each Kitty can only have one approved
- /// address for siring at any time. A zero value means no approval is outstanding.
- mapping (uint256 => address) public sireAllowedToAddress;
-
- /// @dev The address of the ClockAuction contract that handles sales of Kitties. This
- /// same contract handles both peer-to-peer sales as well as the gen0 sales which are
- /// initiated every 15 minutes.
- SaleClockAuction public saleAuction;
-
- /// @dev The address of a custom ClockAuction subclassed contract that handles siring
- /// auctions. Needs to be separate from saleAuction because the actions taken on success
- /// after a sales and siring auction are quite different.
- SiringClockAuction public siringAuction;
-
- /// @dev Assigns ownership of a specific Kitty to an address.
- function _transfer(address _from, address _to, uint256 _tokenId) internal {
- // Since the number of kittens is capped to 2^32 we can't overflow this
- ownershipTokenCount[_to]++;
- // transfer ownership
- kittyIndexToOwner[_tokenId] = _to;
- // When creating new kittens _from is 0x0, but we can't account that address.
- if (_from != address(0)) {
- ownershipTokenCount[_from]--;
- // once the kitten is transferred also clear sire allowances
- delete sireAllowedToAddress[_tokenId];
- // clear any previously approved ownership exchange
- delete kittyIndexToApproved[_tokenId];
- }
- // Emit the transfer event.
- Transfer(_from, _to, _tokenId);
- }
-
- /// @dev An internal method that creates a new kitty and stores it. This
- /// method doesn't do any checking and should only be called when the
- /// input data is known to be valid. Will generate both a Birth event
- /// and a Transfer event.
- /// @param _matronId The kitty ID of the matron of this cat (zero for gen0)
- /// @param _sireId The kitty ID of the sire of this cat (zero for gen0)
- /// @param _generation The generation number of this cat, must be computed by caller.
- /// @param _genes The kitty's genetic code.
- /// @param _owner The inital owner of this cat, must be non-zero (except for the unKitty, ID 0)
- function _createKitty(
- uint256 _matronId,
- uint256 _sireId,
- uint256 _generation,
- uint256 _genes,
- address _owner
- )
- internal
- returns (uint)
- {
- // These requires are not strictly necessary, our calling code should make
- // sure that these conditions are never broken. However! _createKitty() is already
- // an expensive call (for storage), and it doesn't hurt to be especially careful
- // to ensure our data structures are always valid.
- require(_matronId == uint256(uint32(_matronId)));
- require(_sireId == uint256(uint32(_sireId)));
- require(_generation == uint256(uint16(_generation)));
-
- // New kitty starts with the same cooldown as parent gen/2
- uint16 cooldownIndex = uint16(_generation / 2);
- if (cooldownIndex > 13) {
- cooldownIndex = 13;
- }
-
- Kitty memory _kitty = Kitty({
- genes: _genes,
- birthTime: uint64(now),
- cooldownEndBlock: 0,
- matronId: uint32(_matronId),
- sireId: uint32(_sireId),
- siringWithId: 0,
- cooldownIndex: cooldownIndex,
- generation: uint16(_generation)
- });
- uint256 newKittenId = kitties.push(_kitty) - 1;
-
- // It's probably never going to happen, 4 billion cats is A LOT, but
- // let's just be 100% sure we never let this happen.
- require(newKittenId == uint256(uint32(newKittenId)));
-
- // emit the birth event
- Birth(
- _owner,
- newKittenId,
- uint256(_kitty.matronId),
- uint256(_kitty.sireId),
- _kitty.genes
- );
-
- // This will assign ownership, and also emit the Transfer event as
- // per ERC721 draft
- _transfer(0, _owner, newKittenId);
-
- return newKittenId;
- }
-
- // Any C-level can fix how many seconds per blocks are currently observed.
- function setSecondsPerBlock(uint256 secs) external onlyCLevel {
- require(secs < cooldowns[0]);
- secondsPerBlock = secs;
- }
-}
-
-
-
-
-
-/// @title The external contract that is responsible for generating metadata for the kitties,
-/// it has one function that will return the data as bytes.
-contract ERC721Metadata {
- /// @dev Given a token Id, returns a byte array that is supposed to be converted into string.
- function getMetadata(uint256 _tokenId, string) public view returns (bytes32[4] buffer, uint256 count) {
- if (_tokenId == 1) {
- buffer[0] = "Hello World! :D";
- count = 15;
- } else if (_tokenId == 2) {
- buffer[0] = "I would definitely choose a medi";
- buffer[1] = "um length string.";
- count = 49;
- } else if (_tokenId == 3) {
- buffer[0] = "Lorem ipsum dolor sit amet, mi e";
- buffer[1] = "st accumsan dapibus augue lorem,";
- buffer[2] = " tristique vestibulum id, libero";
- buffer[3] = " suscipit varius sapien aliquam.";
- count = 128;
- }
- }
-}
-
-
-/// @title The facet of the CryptoKitties core contract that manages ownership, ERC-721 (draft) compliant.
-/// @author Axiom Zen (https://www.axiomzen.co)
-/// @dev Ref: https://github.com/ethereum/EIPs/issues/721
-/// See the KittyCore contract documentation to understand how the various contract facets are arranged.
-contract KittyOwnership is KittyBase, ERC721 {
-
- /// @notice Name and symbol of the non fungible token, as defined in ERC721.
- string public constant name = "CryptoKitties";
- string public constant symbol = "CK";
-
- // The contract that will return kitty metadata
- ERC721Metadata public erc721Metadata;
-
- bytes4 constant InterfaceSignature_ERC165 =
- bytes4(keccak256('supportsInterface(bytes4)'));
-
- bytes4 constant InterfaceSignature_ERC721 =
- bytes4(keccak256('name()')) ^
- bytes4(keccak256('symbol()')) ^
- bytes4(keccak256('totalSupply()')) ^
- bytes4(keccak256('balanceOf(address)')) ^
- bytes4(keccak256('ownerOf(uint256)')) ^
- bytes4(keccak256('approve(address,uint256)')) ^
- bytes4(keccak256('transfer(address,uint256)')) ^
- bytes4(keccak256('transferFrom(address,address,uint256)')) ^
- bytes4(keccak256('tokensOfOwner(address)')) ^
- bytes4(keccak256('tokenMetadata(uint256,string)'));
-
- /// @notice Introspection interface as per ERC-165 (https://github.com/ethereum/EIPs/issues/165).
- /// Returns true for any standardized interfaces implemented by this contract. We implement
- /// ERC-165 (obviously!) and ERC-721.
- function supportsInterface(bytes4 _interfaceID) external view returns (bool)
- {
- // DEBUG ONLY
- //require((InterfaceSignature_ERC165 == 0x01ffc9a7) && (InterfaceSignature_ERC721 == 0x9a20483d));
-
- return ((_interfaceID == InterfaceSignature_ERC165) || (_interfaceID == InterfaceSignature_ERC721));
- }
-
- /// @dev Set the address of the sibling contract that tracks metadata.
- /// CEO only.
- function setMetadataAddress(address _contractAddress) public onlyCEO {
- erc721Metadata = ERC721Metadata(_contractAddress);
- }
-
- // Internal utility functions: These functions all assume that their input arguments
- // are valid. We leave it to public methods to sanitize their inputs and follow
- // the required logic.
-
- /// @dev Checks if a given address is the current owner of a particular Kitty.
- /// @param _claimant the address we are validating against.
- /// @param _tokenId kitten id, only valid when > 0
- function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
- return kittyIndexToOwner[_tokenId] == _claimant;
- }
-
- /// @dev Checks if a given address currently has transferApproval for a particular Kitty.
- /// @param _claimant the address we are confirming kitten is approved for.
- /// @param _tokenId kitten id, only valid when > 0
- function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) {
- return kittyIndexToApproved[_tokenId] == _claimant;
- }
-
- /// @dev Marks an address as being approved for transferFrom(), overwriting any previous
- /// approval. Setting _approved to address(0) clears all transfer approval.
- /// NOTE: _approve() does NOT send the Approval event. This is intentional because
- /// _approve() and transferFrom() are used together for putting Kitties on auction, and
- /// there is no value in spamming the log with Approval events in that case.
- function _approve(uint256 _tokenId, address _approved) internal {
- kittyIndexToApproved[_tokenId] = _approved;
- }
-
- /// @notice Returns the number of Kitties owned by a specific address.
- /// @param _owner The owner address to check.
- /// @dev Required for ERC-721 compliance
- function balanceOf(address _owner) public view returns (uint256 count) {
- return ownershipTokenCount[_owner];
- }
-
- /// @notice Transfers a Kitty to another address. If transferring to a smart
- /// contract be VERY CAREFUL to ensure that it is aware of ERC-721 (or
- /// CryptoKitties specifically) or your Kitty may be lost forever. Seriously.
- /// @param _to The address of the recipient, can be a user or contract.
- /// @param _tokenId The ID of the Kitty to transfer.
- /// @dev Required for ERC-721 compliance.
- function transfer(
- address _to,
- uint256 _tokenId
- )
- external
- whenNotPaused
- {
- // Safety check to prevent against an unexpected 0x0 default.
- require(_to != address(0));
- // Disallow transfers to this contract to prevent accidental misuse.
- // The contract should never own any kitties (except very briefly
- // after a gen0 cat is created and before it goes on auction).
- require(_to != address(this));
- // Disallow transfers to the auction contracts to prevent accidental
- // misuse. Auction contracts should only take ownership of kitties
- // through the allow + transferFrom flow.
- require(_to != address(saleAuction));
- require(_to != address(siringAuction));
-
- // You can only send your own cat.
- require(_owns(msg.sender, _tokenId));
-
- // Reassign ownership, clear pending approvals, emit Transfer event.
- _transfer(msg.sender, _to, _tokenId);
- }
-
- /// @notice Grant another address the right to transfer a specific Kitty via
- /// transferFrom(). This is the preferred flow for transfering NFTs to contracts.
- /// @param _to The address to be granted transfer approval. Pass address(0) to
- /// clear all approvals.
- /// @param _tokenId The ID of the Kitty that can be transferred if this call succeeds.
- /// @dev Required for ERC-721 compliance.
- function approve(
- address _to,
- uint256 _tokenId
- )
- external
- whenNotPaused
- {
- // Only an owner can grant transfer approval.
- require(_owns(msg.sender, _tokenId));
-
- // Register the approval (replacing any previous approval).
- _approve(_tokenId, _to);
-
- // Emit approval event.
- Approval(msg.sender, _to, _tokenId);
- }
-
- /// @notice Transfer a Kitty owned by another address, for which the calling address
- /// has previously been granted transfer approval by the owner.
- /// @param _from The address that owns the Kitty to be transfered.
- /// @param _to The address that should take ownership of the Kitty. Can be any address,
- /// including the caller.
- /// @param _tokenId The ID of the Kitty to be transferred.
- /// @dev Required for ERC-721 compliance.
- function transferFrom(
- address _from,
- address _to,
- uint256 _tokenId
- )
- external
- whenNotPaused
- {
- // Safety check to prevent against an unexpected 0x0 default.
- require(_to != address(0));
- // Disallow transfers to this contract to prevent accidental misuse.
- // The contract should never own any kitties (except very briefly
- // after a gen0 cat is created and before it goes on auction).
- require(_to != address(this));
- // Check for approval and valid ownership
- require(_approvedFor(msg.sender, _tokenId));
- require(_owns(_from, _tokenId));
-
- // Reassign ownership (also clears pending approvals and emits Transfer event).
- _transfer(_from, _to, _tokenId);
- }
-
- /// @notice Returns the total number of Kitties currently in existence.
- /// @dev Required for ERC-721 compliance.
- function totalSupply() public view returns (uint) {
- return kitties.length - 1;
- }
-
- /// @notice Returns the address currently assigned ownership of a given Kitty.
- /// @dev Required for ERC-721 compliance.
- function ownerOf(uint256 _tokenId)
- external
- view
- returns (address owner)
- {
- owner = kittyIndexToOwner[_tokenId];
-
- require(owner != address(0));
- }
-
- /// @notice Returns a list of all Kitty IDs assigned to an address.
- /// @param _owner The owner whose Kitties we are interested in.
- /// @dev This method MUST NEVER be called by smart contract code. First, it's fairly
- /// expensive (it walks the entire Kitty array looking for cats belonging to owner),
- /// but it also returns a dynamic array, which is only supported for web3 calls, and
- /// not contract-to-contract calls.
- function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) {
- uint256 tokenCount = balanceOf(_owner);
-
- if (tokenCount == 0) {
- // Return an empty array
- return new uint256[](0);
- } else {
- uint256[] memory result = new uint256[](tokenCount);
- uint256 totalCats = totalSupply();
- uint256 resultIndex = 0;
-
- // We count on the fact that all cats have IDs starting at 1 and increasing
- // sequentially up to the totalCat count.
- uint256 catId;
-
- for (catId = 1; catId <= totalCats; catId++) {
- if (kittyIndexToOwner[catId] == _owner) {
- result[resultIndex] = catId;
- resultIndex++;
- }
- }
-
- return result;
- }
- }
-
- /// @dev Adapted from memcpy() by @arachnid (Nick Johnson )
- /// This method is licenced under the Apache License.
- /// Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.sol
- function _memcpy(uint _dest, uint _src, uint _len) private view {
- // Copy word-length chunks while possible
- for(; _len >= 32; _len -= 32) {
- assembly {
- mstore(_dest, mload(_src))
- }
- _dest += 32;
- _src += 32;
- }
-
- // Copy remaining bytes
- uint256 mask = 256 ** (32 - _len) - 1;
- assembly {
- let srcpart := and(mload(_src), not(mask))
- let destpart := and(mload(_dest), mask)
- mstore(_dest, or(destpart, srcpart))
- }
- }
-
- /// @dev Adapted from toString(slice) by @arachnid (Nick Johnson )
- /// This method is licenced under the Apache License.
- /// Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.sol
- function _toString(bytes32[4] _rawBytes, uint256 _stringLength) private view returns (string) {
- var outputString = new string(_stringLength);
- uint256 outputPtr;
- uint256 bytesPtr;
-
- assembly {
- outputPtr := add(outputString, 32)
- bytesPtr := _rawBytes
- }
-
- _memcpy(outputPtr, bytesPtr, _stringLength);
-
- return outputString;
- }
-
- /// @notice Returns a URI pointing to a metadata package for this token conforming to
- /// ERC-721 (https://github.com/ethereum/EIPs/issues/721)
- /// @param _tokenId The ID number of the Kitty whose metadata should be returned.
- function tokenMetadata(uint256 _tokenId, string _preferredTransport) external view returns (string infoUrl) {
- require(erc721Metadata != address(0));
- bytes32[4] memory buffer;
- uint256 count;
- (buffer, count) = erc721Metadata.getMetadata(_tokenId, _preferredTransport);
-
- return _toString(buffer, count);
- }
-}
-
-
-
-/// @title A facet of KittyCore that manages Kitty siring, gestation, and birth.
-/// @author Axiom Zen (https://www.axiomzen.co)
-/// @dev See the KittyCore contract documentation to understand how the various contract facets are arranged.
-contract KittyBreeding is KittyOwnership {
-
- /// @dev The Pregnant event is fired when two cats successfully breed and the pregnancy
- /// timer begins for the matron.
- event Pregnant(address owner, uint256 matronId, uint256 sireId, uint256 cooldownEndBlock);
-
- /// @notice The minimum payment required to use breedWithAuto(). This fee goes towards
- /// the gas cost paid by whatever calls giveBirth(), and can be dynamically updated by
- /// the COO role as the gas price changes.
- uint256 public autoBirthFee = 2 finney;
-
- // Keeps track of number of pregnant kitties.
- uint256 public pregnantKitties;
-
- /// @dev The address of the sibling contract that is used to implement the sooper-sekret
- /// genetic combination algorithm.
- GeneScienceInterface public geneScience;
-
- /// @dev Update the address of the genetic contract, can only be called by the CEO.
- /// @param _address An address of a GeneScience contract instance to be used from this point forward.
- function setGeneScienceAddress(address _address) external onlyCEO {
- GeneScienceInterface candidateContract = GeneScienceInterface(_address);
-
- // NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
- require(candidateContract.isGeneScience());
-
- // Set the new contract address
- geneScience = candidateContract;
- }
-
- /// @dev Checks that a given kitten is able to breed. Requires that the
- /// current cooldown is finished (for sires) and also checks that there is
- /// no pending pregnancy.
- function _isReadyToBreed(Kitty _kit) internal view returns (bool) {
- // In addition to checking the cooldownEndBlock, we also need to check to see if
- // the cat has a pending birth; there can be some period of time between the end
- // of the pregnacy timer and the birth event.
- return (_kit.siringWithId == 0) && (_kit.cooldownEndBlock <= uint64(block.number));
- }
-
- /// @dev Check if a sire has authorized breeding with this matron. True if both sire
- /// and matron have the same owner, or if the sire has given siring permission to
- /// the matron's owner (via approveSiring()).
- function _isSiringPermitted(uint256 _sireId, uint256 _matronId) internal view returns (bool) {
- address matronOwner = kittyIndexToOwner[_matronId];
- address sireOwner = kittyIndexToOwner[_sireId];
-
- // Siring is okay if they have same owner, or if the matron's owner was given
- // permission to breed with this sire.
- return (matronOwner == sireOwner || sireAllowedToAddress[_sireId] == matronOwner);
- }
-
- /// @dev Set the cooldownEndTime for the given Kitty, based on its current cooldownIndex.
- /// Also increments the cooldownIndex (unless it has hit the cap).
- /// @param _kitten A reference to the Kitty in storage which needs its timer started.
- function _triggerCooldown(Kitty storage _kitten) internal {
- // Compute an estimation of the cooldown time in blocks (based on current cooldownIndex).
- _kitten.cooldownEndBlock = uint64((cooldowns[_kitten.cooldownIndex]/secondsPerBlock) + block.number);
-
- // Increment the breeding count, clamping it at 13, which is the length of the
- // cooldowns array. We could check the array size dynamically, but hard-coding
- // this as a constant saves gas. Yay, Solidity!
- if (_kitten.cooldownIndex < 13) {
- _kitten.cooldownIndex += 1;
- }
- }
-
- /// @notice Grants approval to another user to sire with one of your Kitties.
- /// @param _addr The address that will be able to sire with your Kitty. Set to
- /// address(0) to clear all siring approvals for this Kitty.
- /// @param _sireId A Kitty that you own that _addr will now be able to sire with.
- function approveSiring(address _addr, uint256 _sireId)
- external
- whenNotPaused
- {
- require(_owns(msg.sender, _sireId));
- sireAllowedToAddress[_sireId] = _addr;
- }
-
- /// @dev Updates the minimum payment required for calling giveBirthAuto(). Can only
- /// be called by the COO address. (This fee is used to offset the gas cost incurred
- /// by the autobirth daemon).
- function setAutoBirthFee(uint256 val) external onlyCOO {
- autoBirthFee = val;
- }
-
- /// @dev Checks to see if a given Kitty is pregnant and (if so) if the gestation
- /// period has passed.
- function _isReadyToGiveBirth(Kitty _matron) private view returns (bool) {
- return (_matron.siringWithId != 0) && (_matron.cooldownEndBlock <= uint64(block.number));
- }
-
- /// @notice Checks that a given kitten is able to breed (i.e. it is not pregnant or
- /// in the middle of a siring cooldown).
- /// @param _kittyId reference the id of the kitten, any user can inquire about it
- function isReadyToBreed(uint256 _kittyId)
- public
- view
- returns (bool)
- {
- require(_kittyId > 0);
- Kitty storage kit = kitties[_kittyId];
- return _isReadyToBreed(kit);
- }
-
- /// @dev Checks whether a kitty is currently pregnant.
- /// @param _kittyId reference the id of the kitten, any user can inquire about it
- function isPregnant(uint256 _kittyId)
- public
- view
- returns (bool)
- {
- require(_kittyId > 0);
- // A kitty is pregnant if and only if this field is set
- return kitties[_kittyId].siringWithId != 0;
- }
-
- /// @dev Internal check to see if a given sire and matron are a valid mating pair. DOES NOT
- /// check ownership permissions (that is up to the caller).
- /// @param _matron A reference to the Kitty struct of the potential matron.
- /// @param _matronId The matron's ID.
- /// @param _sire A reference to the Kitty struct of the potential sire.
- /// @param _sireId The sire's ID
- function _isValidMatingPair(
- Kitty storage _matron,
- uint256 _matronId,
- Kitty storage _sire,
- uint256 _sireId
- )
- private
- view
- returns(bool)
- {
- // A Kitty can't breed with itself!
- if (_matronId == _sireId) {
- return false;
- }
-
- // Kitties can't breed with their parents.
- if (_matron.matronId == _sireId || _matron.sireId == _sireId) {
- return false;
- }
- if (_sire.matronId == _matronId || _sire.sireId == _matronId) {
- return false;
- }
-
- // We can short circuit the sibling check (below) if either cat is
- // gen zero (has a matron ID of zero).
- if (_sire.matronId == 0 || _matron.matronId == 0) {
- return true;
- }
-
- // Kitties can't breed with full or half siblings.
- if (_sire.matronId == _matron.matronId || _sire.matronId == _matron.sireId) {
- return false;
- }
- if (_sire.sireId == _matron.matronId || _sire.sireId == _matron.sireId) {
- return false;
- }
-
- // Everything seems cool! Let's get DTF.
- return true;
- }
-
- /// @dev Internal check to see if a given sire and matron are a valid mating pair for
- /// breeding via auction (i.e. skips ownership and siring approval checks).
- function _canBreedWithViaAuction(uint256 _matronId, uint256 _sireId)
- internal
- view
- returns (bool)
- {
- Kitty storage matron = kitties[_matronId];
- Kitty storage sire = kitties[_sireId];
- return _isValidMatingPair(matron, _matronId, sire, _sireId);
- }
-
- /// @notice Checks to see if two cats can breed together, including checks for
- /// ownership and siring approvals. Does NOT check that both cats are ready for
- /// breeding (i.e. breedWith could still fail until the cooldowns are finished).
- /// TODO: Shouldn't this check pregnancy and cooldowns?!?
- /// @param _matronId The ID of the proposed matron.
- /// @param _sireId The ID of the proposed sire.
- function canBreedWith(uint256 _matronId, uint256 _sireId)
- external
- view
- returns(bool)
- {
- require(_matronId > 0);
- require(_sireId > 0);
- Kitty storage matron = kitties[_matronId];
- Kitty storage sire = kitties[_sireId];
- return _isValidMatingPair(matron, _matronId, sire, _sireId) &&
- _isSiringPermitted(_sireId, _matronId);
- }
-
- /// @dev Internal utility function to initiate breeding, assumes that all breeding
- /// requirements have been checked.
- function _breedWith(uint256 _matronId, uint256 _sireId) internal {
- // Grab a reference to the Kitties from storage.
- Kitty storage sire = kitties[_sireId];
- Kitty storage matron = kitties[_matronId];
-
- // Mark the matron as pregnant, keeping track of who the sire is.
- matron.siringWithId = uint32(_sireId);
-
- // Trigger the cooldown for both parents.
- _triggerCooldown(sire);
- _triggerCooldown(matron);
-
- // Clear siring permission for both parents. This may not be strictly necessary
- // but it's likely to avoid confusion!
- delete sireAllowedToAddress[_matronId];
- delete sireAllowedToAddress[_sireId];
-
- // Every time a kitty gets pregnant, counter is incremented.
- pregnantKitties++;
-
- // Emit the pregnancy event.
- Pregnant(kittyIndexToOwner[_matronId], _matronId, _sireId, matron.cooldownEndBlock);
- }
-
- /// @notice Breed a Kitty you own (as matron) with a sire that you own, or for which you
- /// have previously been given Siring approval. Will either make your cat pregnant, or will
- /// fail entirely. Requires a pre-payment of the fee given out to the first caller of giveBirth()
- /// @param _matronId The ID of the Kitty acting as matron (will end up pregnant if successful)
- /// @param _sireId The ID of the Kitty acting as sire (will begin its siring cooldown if successful)
- function breedWithAuto(uint256 _matronId, uint256 _sireId)
- external
- payable
- whenNotPaused
- {
- // Checks for payment.
- require(msg.value >= autoBirthFee);
-
- // Caller must own the matron.
- require(_owns(msg.sender, _matronId));
-
- // Neither sire nor matron are allowed to be on auction during a normal
- // breeding operation, but we don't need to check that explicitly.
- // For matron: The caller of this function can't be the owner of the matron
- // because the owner of a Kitty on auction is the auction house, and the
- // auction house will never call breedWith().
- // For sire: Similarly, a sire on auction will be owned by the auction house
- // and the act of transferring ownership will have cleared any oustanding
- // siring approval.
- // Thus we don't need to spend gas explicitly checking to see if either cat
- // is on auction.
-
- // Check that matron and sire are both owned by caller, or that the sire
- // has given siring permission to caller (i.e. matron's owner).
- // Will fail for _sireId = 0
- require(_isSiringPermitted(_sireId, _matronId));
-
- // Grab a reference to the potential matron
- Kitty storage matron = kitties[_matronId];
-
- // Make sure matron isn't pregnant, or in the middle of a siring cooldown
- require(_isReadyToBreed(matron));
-
- // Grab a reference to the potential sire
- Kitty storage sire = kitties[_sireId];
-
- // Make sure sire isn't pregnant, or in the middle of a siring cooldown
- require(_isReadyToBreed(sire));
-
- // Test that these cats are a valid mating pair.
- require(_isValidMatingPair(
- matron,
- _matronId,
- sire,
- _sireId
- ));
-
- // All checks passed, kitty gets pregnant!
- _breedWith(_matronId, _sireId);
- }
-
- /// @notice Have a pregnant Kitty give birth!
- /// @param _matronId A Kitty ready to give birth.
- /// @return The Kitty ID of the new kitten.
- /// @dev Looks at a given Kitty and, if pregnant and if the gestation period has passed,
- /// combines the genes of the two parents to create a new kitten. The new Kitty is assigned
- /// to the current owner of the matron. Upon successful completion, both the matron and the
- /// new kitten will be ready to breed again. Note that anyone can call this function (if they
- /// are willing to pay the gas!), but the new kitten always goes to the mother's owner.
- function giveBirth(uint256 _matronId)
- external
- whenNotPaused
- returns(uint256)
- {
- // Grab a reference to the matron in storage.
- Kitty storage matron = kitties[_matronId];
-
- // Check that the matron is a valid cat.
- require(matron.birthTime != 0);
-
- // Check that the matron is pregnant, and that its time has come!
- require(_isReadyToGiveBirth(matron));
-
- // Grab a reference to the sire in storage.
- uint256 sireId = matron.siringWithId;
- Kitty storage sire = kitties[sireId];
-
- // Determine the higher generation number of the two parents
- uint16 parentGen = matron.generation;
- if (sire.generation > matron.generation) {
- parentGen = sire.generation;
- }
-
- // Call the sooper-sekret gene mixing operation.
- uint256 childGenes = geneScience.mixGenes(matron.genes, sire.genes, matron.cooldownEndBlock - 1);
-
- // Make the new kitten!
- address owner = kittyIndexToOwner[_matronId];
- uint256 kittenId = _createKitty(_matronId, matron.siringWithId, parentGen + 1, childGenes, owner);
-
- // Clear the reference to sire from the matron (REQUIRED! Having siringWithId
- // set is what marks a matron as being pregnant.)
- delete matron.siringWithId;
-
- // Every time a kitty gives birth counter is decremented.
- pregnantKitties--;
-
- // Send the balance fee to the person who made birth happen.
- msg.sender.send(autoBirthFee);
-
- // return the new kitten's ID
- return kittenId;
- }
-}
-
-
-
-
-
-
-
-
-
-
-/// @title Auction Core
-/// @dev Contains models, variables, and internal methods for the auction.
-/// @notice We omit a fallback function to prevent accidental sends to this contract.
-contract ClockAuctionBase {
-
- // Represents an auction on an NFT
- struct Auction {
- // Current owner of NFT
- address seller;
- // Price (in wei) at beginning of auction
- uint128 startingPrice;
- // Price (in wei) at end of auction
- uint128 endingPrice;
- // Duration (in seconds) of auction
- uint64 duration;
- // Time when auction started
- // NOTE: 0 if this auction has been concluded
- uint64 startedAt;
- }
-
- // Reference to contract tracking NFT ownership
- ERC721 public nonFungibleContract;
-
- // Cut owner takes on each auction, measured in basis points (1/100 of a percent).
- // Values 0-10,000 map to 0%-100%
- uint256 public ownerCut;
-
- // Map from token ID to their corresponding auction.
- mapping (uint256 => Auction) tokenIdToAuction;
-
- event AuctionCreated(uint256 tokenId, uint256 startingPrice, uint256 endingPrice, uint256 duration);
- event AuctionSuccessful(uint256 tokenId, uint256 totalPrice, address winner);
- event AuctionCancelled(uint256 tokenId);
-
- /// @dev Returns true if the claimant owns the token.
- /// @param _claimant - Address claiming to own the token.
- /// @param _tokenId - ID of token whose ownership to verify.
- function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) {
- return (nonFungibleContract.ownerOf(_tokenId) == _claimant);
- }
-
- /// @dev Escrows the NFT, assigning ownership to this contract.
- /// Throws if the escrow fails.
- /// @param _owner - Current owner address of token to escrow.
- /// @param _tokenId - ID of token whose approval to verify.
- function _escrow(address _owner, uint256 _tokenId) internal {
- // it will throw if transfer fails
- nonFungibleContract.transferFrom(_owner, this, _tokenId);
- }
-
- /// @dev Transfers an NFT owned by this contract to another address.
- /// Returns true if the transfer succeeds.
- /// @param _receiver - Address to transfer NFT to.
- /// @param _tokenId - ID of token to transfer.
- function _transfer(address _receiver, uint256 _tokenId) internal {
- // it will throw if transfer fails
- nonFungibleContract.transfer(_receiver, _tokenId);
- }
-
- /// @dev Adds an auction to the list of open auctions. Also fires the
- /// AuctionCreated event.
- /// @param _tokenId The ID of the token to be put on auction.
- /// @param _auction Auction to add.
- function _addAuction(uint256 _tokenId, Auction _auction) internal {
- // Require that all auctions have a duration of
- // at least one minute. (Keeps our math from getting hairy!)
- require(_auction.duration >= 1 minutes);
-
- tokenIdToAuction[_tokenId] = _auction;
-
- AuctionCreated(
- uint256(_tokenId),
- uint256(_auction.startingPrice),
- uint256(_auction.endingPrice),
- uint256(_auction.duration)
- );
- }
-
- /// @dev Cancels an auction unconditionally.
- function _cancelAuction(uint256 _tokenId, address _seller) internal {
- _removeAuction(_tokenId);
- _transfer(_seller, _tokenId);
- AuctionCancelled(_tokenId);
- }
-
- /// @dev Computes the price and transfers winnings.
- /// Does NOT transfer ownership of token.
- function _bid(uint256 _tokenId, uint256 _bidAmount)
- internal
- returns (uint256)
- {
- // Get a reference to the auction struct
- Auction storage auction = tokenIdToAuction[_tokenId];
-
- // Explicitly check that this auction is currently live.
- // (Because of how Ethereum mappings work, we can't just count
- // on the lookup above failing. An invalid _tokenId will just
- // return an auction object that is all zeros.)
- require(_isOnAuction(auction));
-
- // Check that the bid is greater than or equal to the current price
- uint256 price = _currentPrice(auction);
- require(_bidAmount >= price);
-
- // Grab a reference to the seller before the auction struct
- // gets deleted.
- address seller = auction.seller;
-
- // The bid is good! Remove the auction before sending the fees
- // to the sender so we can't have a reentrancy attack.
- _removeAuction(_tokenId);
-
- // Transfer proceeds to seller (if there are any!)
- if (price > 0) {
- // Calculate the auctioneer's cut.
- // (NOTE: _computeCut() is guaranteed to return a
- // value <= price, so this subtraction can't go negative.)
- uint256 auctioneerCut = _computeCut(price);
- uint256 sellerProceeds = price - auctioneerCut;
-
- // NOTE: Doing a transfer() in the middle of a complex
- // method like this is generally discouraged because of
- // reentrancy attacks and DoS attacks if the seller is
- // a contract with an invalid fallback function. We explicitly
- // guard against reentrancy attacks by removing the auction
- // before calling transfer(), and the only thing the seller
- // can DoS is the sale of their own asset! (And if it's an
- // accident, they can call cancelAuction(). )
- seller.transfer(sellerProceeds);
- }
-
- // Calculate any excess funds included with the bid. If the excess
- // is anything worth worrying about, transfer it back to bidder.
- // NOTE: We checked above that the bid amount is greater than or
- // equal to the price so this cannot underflow.
- uint256 bidExcess = _bidAmount - price;
-
- // Return the funds. Similar to the previous transfer, this is
- // not susceptible to a re-entry attack because the auction is
- // removed before any transfers occur.
- msg.sender.transfer(bidExcess);
-
- // Tell the world!
- AuctionSuccessful(_tokenId, price, msg.sender);
-
- return price;
- }
-
- /// @dev Removes an auction from the list of open auctions.
- /// @param _tokenId - ID of NFT on auction.
- function _removeAuction(uint256 _tokenId) internal {
- delete tokenIdToAuction[_tokenId];
- }
-
- /// @dev Returns true if the NFT is on auction.
- /// @param _auction - Auction to check.
- function _isOnAuction(Auction storage _auction) internal view returns (bool) {
- return (_auction.startedAt > 0);
- }
-
- /// @dev Returns current price of an NFT on auction. Broken into two
- /// functions (this one, that computes the duration from the auction
- /// structure, and the other that does the price computation) so we
- /// can easily test that the price computation works correctly.
- function _currentPrice(Auction storage _auction)
- internal
- view
- returns (uint256)
- {
- uint256 secondsPassed = 0;
-
- // A bit of insurance against negative values (or wraparound).
- // Probably not necessary (since Ethereum guarnatees that the
- // now variable doesn't ever go backwards).
- if (now > _auction.startedAt) {
- secondsPassed = now - _auction.startedAt;
- }
-
- return _computeCurrentPrice(
- _auction.startingPrice,
- _auction.endingPrice,
- _auction.duration,
- secondsPassed
- );
- }
-
- /// @dev Computes the current price of an auction. Factored out
- /// from _currentPrice so we can run extensive unit tests.
- /// When testing, make this function public and turn on
- /// `Current price computation` test suite.
- function _computeCurrentPrice(
- uint256 _startingPrice,
- uint256 _endingPrice,
- uint256 _duration,
- uint256 _secondsPassed
- )
- internal
- pure
- returns (uint256)
- {
- // NOTE: We don't use SafeMath (or similar) in this function because
- // all of our public functions carefully cap the maximum values for
- // time (at 64-bits) and currency (at 128-bits). _duration is
- // also known to be non-zero (see the require() statement in
- // _addAuction())
- if (_secondsPassed >= _duration) {
- // We've reached the end of the dynamic pricing portion
- // of the auction, just return the end price.
- return _endingPrice;
- } else {
- // Starting price can be higher than ending price (and often is!), so
- // this delta can be negative.
- int256 totalPriceChange = int256(_endingPrice) - int256(_startingPrice);
-
- // This multiplication can't overflow, _secondsPassed will easily fit within
- // 64-bits, and totalPriceChange will easily fit within 128-bits, their product
- // will always fit within 256-bits.
- int256 currentPriceChange = totalPriceChange * int256(_secondsPassed) / int256(_duration);
-
- // currentPriceChange can be negative, but if so, will have a magnitude
- // less that _startingPrice. Thus, this result will always end up positive.
- int256 currentPrice = int256(_startingPrice) + currentPriceChange;
-
- return uint256(currentPrice);
- }
- }
-
- /// @dev Computes owner's cut of a sale.
- /// @param _price - Sale price of NFT.
- function _computeCut(uint256 _price) internal view returns (uint256) {
- // NOTE: We don't use SafeMath (or similar) in this function because
- // all of our entry functions carefully cap the maximum values for
- // currency (at 128-bits), and ownerCut <= 10000 (see the require()
- // statement in the ClockAuction constructor). The result of this
- // function is always guaranteed to be <= _price.
- return _price * ownerCut / 10000;
- }
-
-}
-
-
-
-
-
-
-
-/**
- * @title Pausable
- * @dev Base contract which allows children to implement an emergency stop mechanism.
- */
-contract Pausable is Ownable {
- event Pause();
- event Unpause();
-
- bool public paused = false;
-
-
- /**
- * @dev modifier to allow actions only when the contract IS paused
- */
- modifier whenNotPaused() {
- require(!paused);
- _;
- }
-
- /**
- * @dev modifier to allow actions only when the contract IS NOT paused
- */
- modifier whenPaused {
- require(paused);
- _;
- }
-
- /**
- * @dev called by the owner to pause, triggers stopped state
- */
- function pause() onlyOwner whenNotPaused returns (bool) {
- paused = true;
- Pause();
- return true;
- }
-
- /**
- * @dev called by the owner to unpause, returns to normal state
- */
- function unpause() onlyOwner whenPaused returns (bool) {
- paused = false;
- Unpause();
- return true;
- }
-}
-
-
-/// @title Clock auction for non-fungible tokens.
-/// @notice We omit a fallback function to prevent accidental sends to this contract.
-contract ClockAuction is Pausable, ClockAuctionBase {
-
- /// @dev The ERC-165 interface signature for ERC-721.
- /// Ref: https://github.com/ethereum/EIPs/issues/165
- /// Ref: https://github.com/ethereum/EIPs/issues/721
- bytes4 constant InterfaceSignature_ERC721 = bytes4(0x9a20483d);
-
- /// @dev Constructor creates a reference to the NFT ownership contract
- /// and verifies the owner cut is in the valid range.
- /// @param _nftAddress - address of a deployed contract implementing
- /// the Nonfungible Interface.
- /// @param _cut - percent cut the owner takes on each auction, must be
- /// between 0-10,000.
- function ClockAuction(address _nftAddress, uint256 _cut) public {
- require(_cut <= 10000);
- ownerCut = _cut;
-
- ERC721 candidateContract = ERC721(_nftAddress);
- require(candidateContract.supportsInterface(InterfaceSignature_ERC721));
- nonFungibleContract = candidateContract;
- }
-
- /// @dev Remove all Ether from the contract, which is the owner's cuts
- /// as well as any Ether sent directly to the contract address.
- /// Always transfers to the NFT contract, but can be called either by
- /// the owner or the NFT contract.
- function withdrawBalance() external {
- address nftAddress = address(nonFungibleContract);
-
- require(
- msg.sender == owner ||
- msg.sender == nftAddress
- );
- // We are using this boolean method to make sure that even if one fails it will still work
- bool res = nftAddress.send(this.balance);
- }
-
- /// @dev Creates and begins a new auction.
- /// @param _tokenId - ID of token to auction, sender must be owner.
- /// @param _startingPrice - Price of item (in wei) at beginning of auction.
- /// @param _endingPrice - Price of item (in wei) at end of auction.
- /// @param _duration - Length of time to move between starting
- /// price and ending price (in seconds).
- /// @param _seller - Seller, if not the message sender
- function createAuction(
- uint256 _tokenId,
- uint256 _startingPrice,
- uint256 _endingPrice,
- uint256 _duration,
- address _seller
- )
- external
- whenNotPaused
- {
- // Sanity check that no inputs overflow how many bits we've allocated
- // to store them in the auction struct.
- require(_startingPrice == uint256(uint128(_startingPrice)));
- require(_endingPrice == uint256(uint128(_endingPrice)));
- require(_duration == uint256(uint64(_duration)));
-
- require(_owns(msg.sender, _tokenId));
- _escrow(msg.sender, _tokenId);
- Auction memory auction = Auction(
- _seller,
- uint128(_startingPrice),
- uint128(_endingPrice),
- uint64(_duration),
- uint64(now)
- );
- _addAuction(_tokenId, auction);
- }
-
- /// @dev Bids on an open auction, completing the auction and transferring
- /// ownership of the NFT if enough Ether is supplied.
- /// @param _tokenId - ID of token to bid on.
- function bid(uint256 _tokenId)
- external
- payable
- whenNotPaused
- {
- // _bid will throw if the bid or funds transfer fails
- _bid(_tokenId, msg.value);
- _transfer(msg.sender, _tokenId);
- }
-
- /// @dev Cancels an auction that hasn't been won yet.
- /// Returns the NFT to original owner.
- /// @notice This is a state-modifying function that can
- /// be called while the contract is paused.
- /// @param _tokenId - ID of token on auction
- function cancelAuction(uint256 _tokenId)
- external
- {
- Auction storage auction = tokenIdToAuction[_tokenId];
- require(_isOnAuction(auction));
- address seller = auction.seller;
- require(msg.sender == seller);
- _cancelAuction(_tokenId, seller);
- }
-
- /// @dev Cancels an auction when the contract is paused.
- /// Only the owner may do this, and NFTs are returned to
- /// the seller. This should only be used in emergencies.
- /// @param _tokenId - ID of the NFT on auction to cancel.
- function cancelAuctionWhenPaused(uint256 _tokenId)
- whenPaused
- onlyOwner
- external
- {
- Auction storage auction = tokenIdToAuction[_tokenId];
- require(_isOnAuction(auction));
- _cancelAuction(_tokenId, auction.seller);
- }
-
- /// @dev Returns auction info for an NFT on auction.
- /// @param _tokenId - ID of NFT on auction.
- function getAuction(uint256 _tokenId)
- external
- view
- returns
- (
- address seller,
- uint256 startingPrice,
- uint256 endingPrice,
- uint256 duration,
- uint256 startedAt
- ) {
- Auction storage auction = tokenIdToAuction[_tokenId];
- require(_isOnAuction(auction));
- return (
- auction.seller,
- auction.startingPrice,
- auction.endingPrice,
- auction.duration,
- auction.startedAt
- );
- }
-
- /// @dev Returns the current price of an auction.
- /// @param _tokenId - ID of the token price we are checking.
- function getCurrentPrice(uint256 _tokenId)
- external
- view
- returns (uint256)
- {
- Auction storage auction = tokenIdToAuction[_tokenId];
- require(_isOnAuction(auction));
- return _currentPrice(auction);
- }
-
-}
-
-
-/// @title Reverse auction modified for siring
-/// @notice We omit a fallback function to prevent accidental sends to this contract.
-contract SiringClockAuction is ClockAuction {
-
- // @dev Sanity check that allows us to ensure that we are pointing to the
- // right auction in our setSiringAuctionAddress() call.
- bool public isSiringClockAuction = true;
-
- // Delegate constructor
- function SiringClockAuction(address _nftAddr, uint256 _cut) public
- ClockAuction(_nftAddr, _cut) {}
-
- /// @dev Creates and begins a new auction. Since this function is wrapped,
- /// require sender to be KittyCore contract.
- /// @param _tokenId - ID of token to auction, sender must be owner.
- /// @param _startingPrice - Price of item (in wei) at beginning of auction.
- /// @param _endingPrice - Price of item (in wei) at end of auction.
- /// @param _duration - Length of auction (in seconds).
- /// @param _seller - Seller, if not the message sender
- function createAuction(
- uint256 _tokenId,
- uint256 _startingPrice,
- uint256 _endingPrice,
- uint256 _duration,
- address _seller
- )
- external
- {
- // Sanity check that no inputs overflow how many bits we've allocated
- // to store them in the auction struct.
- require(_startingPrice == uint256(uint128(_startingPrice)));
- require(_endingPrice == uint256(uint128(_endingPrice)));
- require(_duration == uint256(uint64(_duration)));
-
- require(msg.sender == address(nonFungibleContract));
- _escrow(_seller, _tokenId);
- Auction memory auction = Auction(
- _seller,
- uint128(_startingPrice),
- uint128(_endingPrice),
- uint64(_duration),
- uint64(now)
- );
- _addAuction(_tokenId, auction);
- }
-
- /// @dev Places a bid for siring. Requires the sender
- /// is the KittyCore contract because all bid methods
- /// should be wrapped. Also returns the kitty to the
- /// seller rather than the winner.
- function bid(uint256 _tokenId)
- external
- payable
- {
- require(msg.sender == address(nonFungibleContract));
- address seller = tokenIdToAuction[_tokenId].seller;
- // _bid checks that token ID is valid and will throw if bid fails
- _bid(_tokenId, msg.value);
- // We transfer the kitty back to the seller, the winner will get
- // the offspring
- _transfer(seller, _tokenId);
- }
-
-}
-
-
-
-
-
-/// @title Clock auction modified for sale of kitties
-/// @notice We omit a fallback function to prevent accidental sends to this contract.
-contract SaleClockAuction is ClockAuction {
-
- // @dev Sanity check that allows us to ensure that we are pointing to the
- // right auction in our setSaleAuctionAddress() call.
- bool public isSaleClockAuction = true;
-
- // Tracks last 5 sale price of gen0 kitty sales
- uint256 public gen0SaleCount;
- uint256[5] public lastGen0SalePrices;
-
- // Delegate constructor
- function SaleClockAuction(address _nftAddr, uint256 _cut) public
- ClockAuction(_nftAddr, _cut) {}
-
- /// @dev Creates and begins a new auction.
- /// @param _tokenId - ID of token to auction, sender must be owner.
- /// @param _startingPrice - Price of item (in wei) at beginning of auction.
- /// @param _endingPrice - Price of item (in wei) at end of auction.
- /// @param _duration - Length of auction (in seconds).
- /// @param _seller - Seller, if not the message sender
- function createAuction(
- uint256 _tokenId,
- uint256 _startingPrice,
- uint256 _endingPrice,
- uint256 _duration,
- address _seller
- )
- external
- {
- // Sanity check that no inputs overflow how many bits we've allocated
- // to store them in the auction struct.
- require(_startingPrice == uint256(uint128(_startingPrice)));
- require(_endingPrice == uint256(uint128(_endingPrice)));
- require(_duration == uint256(uint64(_duration)));
-
- require(msg.sender == address(nonFungibleContract));
- _escrow(_seller, _tokenId);
- Auction memory auction = Auction(
- _seller,
- uint128(_startingPrice),
- uint128(_endingPrice),
- uint64(_duration),
- uint64(now)
- );
- _addAuction(_tokenId, auction);
- }
-
- /// @dev Updates lastSalePrice if seller is the nft contract
- /// Otherwise, works the same as default bid method.
- function bid(uint256 _tokenId)
- external
- payable
- {
- // _bid verifies token ID size
- address seller = tokenIdToAuction[_tokenId].seller;
- uint256 price = _bid(_tokenId, msg.value);
- _transfer(msg.sender, _tokenId);
-
- // If not a gen0 auction, exit
- if (seller == address(nonFungibleContract)) {
- // Track gen0 sale prices
- lastGen0SalePrices[gen0SaleCount % 5] = price;
- gen0SaleCount++;
- }
- }
-
- function averageGen0SalePrice() external view returns (uint256) {
- uint256 sum = 0;
- for (uint256 i = 0; i < 5; i++) {
- sum += lastGen0SalePrices[i];
- }
- return sum / 5;
- }
-
-}
-
-
-/// @title Handles creating auctions for sale and siring of kitties.
-/// This wrapper of ReverseAuction exists only so that users can create
-/// auctions with only one transaction.
-contract KittyAuction is KittyBreeding {
-
- // @notice The auction contract variables are defined in KittyBase to allow
- // us to refer to them in KittyOwnership to prevent accidental transfers.
- // `saleAuction` refers to the auction for gen0 and p2p sale of kitties.
- // `siringAuction` refers to the auction for siring rights of kitties.
-
- /// @dev Sets the reference to the sale auction.
- /// @param _address - Address of sale contract.
- function setSaleAuctionAddress(address _address) external onlyCEO {
- SaleClockAuction candidateContract = SaleClockAuction(_address);
-
- // NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
- require(candidateContract.isSaleClockAuction());
-
- // Set the new contract address
- saleAuction = candidateContract;
- }
-
- /// @dev Sets the reference to the siring auction.
- /// @param _address - Address of siring contract.
- function setSiringAuctionAddress(address _address) external onlyCEO {
- SiringClockAuction candidateContract = SiringClockAuction(_address);
-
- // NOTE: verify that a contract is what we expect - https://github.com/Lunyr/crowdsale-contracts/blob/cfadd15986c30521d8ba7d5b6f57b4fefcc7ac38/contracts/LunyrToken.sol#L117
- require(candidateContract.isSiringClockAuction());
-
- // Set the new contract address
- siringAuction = candidateContract;
- }
-
- /// @dev Put a kitty up for auction.
- /// Does some ownership trickery to create auctions in one tx.
- function createSaleAuction(
- uint256 _kittyId,
- uint256 _startingPrice,
- uint256 _endingPrice,
- uint256 _duration
- )
- external
- whenNotPaused
- {
- // Auction contract checks input sizes
- // If kitty is already on any auction, this will throw
- // because it will be owned by the auction contract.
- require(_owns(msg.sender, _kittyId));
- // Ensure the kitty is not pregnant to prevent the auction
- // contract accidentally receiving ownership of the child.
- // NOTE: the kitty IS allowed to be in a cooldown.
- require(!isPregnant(_kittyId));
- _approve(_kittyId, saleAuction);
- // Sale auction throws if inputs are invalid and clears
- // transfer and sire approval after escrowing the kitty.
- saleAuction.createAuction(
- _kittyId,
- _startingPrice,
- _endingPrice,
- _duration,
- msg.sender
- );
- }
-
- /// @dev Put a kitty up for auction to be sire.
- /// Performs checks to ensure the kitty can be sired, then
- /// delegates to reverse auction.
- function createSiringAuction(
- uint256 _kittyId,
- uint256 _startingPrice,
- uint256 _endingPrice,
- uint256 _duration
- )
- external
- whenNotPaused
- {
- // Auction contract checks input sizes
- // If kitty is already on any auction, this will throw
- // because it will be owned by the auction contract.
- require(_owns(msg.sender, _kittyId));
- require(isReadyToBreed(_kittyId));
- _approve(_kittyId, siringAuction);
- // Siring auction throws if inputs are invalid and clears
- // transfer and sire approval after escrowing the kitty.
- siringAuction.createAuction(
- _kittyId,
- _startingPrice,
- _endingPrice,
- _duration,
- msg.sender
- );
- }
-
- /// @dev Completes a siring auction by bidding.
- /// Immediately breeds the winning matron with the sire on auction.
- /// @param _sireId - ID of the sire on auction.
- /// @param _matronId - ID of the matron owned by the bidder.
- function bidOnSiringAuction(
- uint256 _sireId,
- uint256 _matronId
- )
- external
- payable
- whenNotPaused
- {
- // Auction contract checks input sizes
- require(_owns(msg.sender, _matronId));
- require(isReadyToBreed(_matronId));
- require(_canBreedWithViaAuction(_matronId, _sireId));
-
- // Define the current price of the auction.
- uint256 currentPrice = siringAuction.getCurrentPrice(_sireId);
- require(msg.value >= currentPrice + autoBirthFee);
-
- // Siring auction will throw if the bid fails.
- siringAuction.bid.value(msg.value - autoBirthFee)(_sireId);
- _breedWith(uint32(_matronId), uint32(_sireId));
- }
-
- /// @dev Transfers the balance of the sale auction contract
- /// to the KittyCore contract. We use two-step withdrawal to
- /// prevent two transfer calls in the auction bid function.
- function withdrawAuctionBalances() external onlyCLevel {
- saleAuction.withdrawBalance();
- siringAuction.withdrawBalance();
- }
-}
-
-
-/// @title all functions related to creating kittens
-contract KittyMinting is KittyAuction {
-
- // Limits the number of cats the contract owner can ever create.
- uint256 public constant PROMO_CREATION_LIMIT = 5000;
- uint256 public constant GEN0_CREATION_LIMIT = 45000;
-
- // Constants for gen0 auctions.
- uint256 public constant GEN0_STARTING_PRICE = 10 finney;
- uint256 public constant GEN0_AUCTION_DURATION = 1 days;
-
- // Counts the number of cats the contract owner has created.
- uint256 public promoCreatedCount;
- uint256 public gen0CreatedCount;
-
- /// @dev we can create promo kittens, up to a limit. Only callable by COO
- /// @param _genes the encoded genes of the kitten to be created, any value is accepted
- /// @param _owner the future owner of the created kittens. Default to contract COO
- function createPromoKitty(uint256 _genes, address _owner) external onlyCOO {
- address kittyOwner = _owner;
- if (kittyOwner == address(0)) {
- kittyOwner = cooAddress;
- }
- require(promoCreatedCount < PROMO_CREATION_LIMIT);
-
- promoCreatedCount++;
- _createKitty(0, 0, 0, _genes, kittyOwner);
- }
-
- /// @dev Creates a new gen0 kitty with the given genes and
- /// creates an auction for it.
- function createGen0Auction(uint256 _genes) external onlyCOO {
- require(gen0CreatedCount < GEN0_CREATION_LIMIT);
-
- uint256 kittyId = _createKitty(0, 0, 0, _genes, address(this));
- _approve(kittyId, saleAuction);
-
- saleAuction.createAuction(
- kittyId,
- _computeNextGen0Price(),
- 0,
- GEN0_AUCTION_DURATION,
- address(this)
- );
-
- gen0CreatedCount++;
- }
-
- /// @dev Computes the next gen0 auction starting price, given
- /// the average of the past 5 prices + 50%.
- function _computeNextGen0Price() internal view returns (uint256) {
- uint256 avePrice = saleAuction.averageGen0SalePrice();
-
- // Sanity check to ensure we don't overflow arithmetic
- require(avePrice == uint256(uint128(avePrice)));
-
- uint256 nextPrice = avePrice + (avePrice / 2);
-
- // We never auction for less than starting price
- if (nextPrice < GEN0_STARTING_PRICE) {
- nextPrice = GEN0_STARTING_PRICE;
- }
-
- return nextPrice;
- }
-}
-
-
-/// @title CryptoKitties: Collectible, breedable, and oh-so-adorable cats on the Ethereum blockchain.
-/// @author Axiom Zen (https://www.axiomzen.co)
-/// @dev The main CryptoKitties contract, keeps track of kittens so they don't wander around and get lost.
-contract KittyCore is KittyMinting {
-
- // This is the main CryptoKitties contract. In order to keep our code seperated into logical sections,
- // we've broken it up in two ways. First, we have several seperately-instantiated sibling contracts
- // that handle auctions and our super-top-secret genetic combination algorithm. The auctions are
- // seperate since their logic is somewhat complex and there's always a risk of subtle bugs. By keeping
- // them in their own contracts, we can upgrade them without disrupting the main contract that tracks
- // kitty ownership. The genetic combination algorithm is kept seperate so we can open-source all of
- // the rest of our code without making it _too_ easy for folks to figure out how the genetics work.
- // Don't worry, I'm sure someone will reverse engineer it soon enough!
- //
- // Secondly, we break the core contract into multiple files using inheritence, one for each major
- // facet of functionality of CK. This allows us to keep related code bundled together while still
- // avoiding a single giant file with everything in it. The breakdown is as follows:
- //
- // - KittyBase: This is where we define the most fundamental code shared throughout the core
- // functionality. This includes our main data storage, constants and data types, plus
- // internal functions for managing these items.
- //
- // - KittyAccessControl: This contract manages the various addresses and constraints for operations
- // that can be executed only by specific roles. Namely CEO, CFO and COO.
- //
- // - KittyOwnership: This provides the methods required for basic non-fungible token
- // transactions, following the draft ERC-721 spec (https://github.com/ethereum/EIPs/issues/721).
- //
- // - KittyBreeding: This file contains the methods necessary to breed cats together, including
- // keeping track of siring offers, and relies on an external genetic combination contract.
- //
- // - KittyAuctions: Here we have the public methods for auctioning or bidding on cats or siring
- // services. The actual auction functionality is handled in two sibling contracts (one
- // for sales and one for siring), while auction creation and bidding is mostly mediated
- // through this facet of the core contract.
- //
- // - KittyMinting: This final facet contains the functionality we use for creating new gen0 cats.
- // We can make up to 5000 "promo" cats that can be given away (especially important when
- // the community is new), and all others can only be created and then immediately put up
- // for auction via an algorithmically determined starting price. Regardless of how they
- // are created, there is a hard limit of 50k gen0 cats. After that, it's all up to the
- // community to breed, breed, breed!
-
- // Set in case the core contract is broken and an upgrade is required
- address public newContractAddress;
-
- /// @notice Creates the main CryptoKitties smart contract instance.
- function KittyCore() public {
- // Starts paused.
- paused = true;
-
- // the creator of the contract is the initial CEO
- ceoAddress = msg.sender;
-
- // the creator of the contract is also the initial COO
- cooAddress = msg.sender;
-
- // start with the mythical kitten 0 - so we don't have generation-0 parent issues
- _createKitty(0, 0, 0, uint256(-1), address(0));
- }
-
- /// @dev Used to mark the smart contract as upgraded, in case there is a serious
- /// breaking bug. This method does nothing but keep track of the new contract and
- /// emit a message indicating that the new address is set. It's up to clients of this
- /// contract to update to the new contract address in that case. (This contract will
- /// be paused indefinitely if such an upgrade takes place.)
- /// @param _v2Address new address
- function setNewAddress(address _v2Address) external onlyCEO whenPaused {
- // See README.md for updgrade plan
- newContractAddress = _v2Address;
- ContractUpgrade(_v2Address);
- }
-
- /// @notice No tipping!
- /// @dev Reject all Ether from being sent here, unless it's from one of the
- /// two auction contracts. (Hopefully, we can prevent user accidents.)
- function() external payable {
- require(
- msg.sender == address(saleAuction) ||
- msg.sender == address(siringAuction)
- );
- }
-
- /// @notice Returns all the relevant information about a specific kitty.
- /// @param _id The ID of the kitty of interest.
- function getKitty(uint256 _id)
- external
- view
- returns (
- bool isGestating,
- bool isReady,
- uint256 cooldownIndex,
- uint256 nextActionAt,
- uint256 siringWithId,
- uint256 birthTime,
- uint256 matronId,
- uint256 sireId,
- uint256 generation,
- uint256 genes
- ) {
- Kitty storage kit = kitties[_id];
-
- // if this variable is 0 then it's not gestating
- isGestating = (kit.siringWithId != 0);
- isReady = (kit.cooldownEndBlock <= block.number);
- cooldownIndex = uint256(kit.cooldownIndex);
- nextActionAt = uint256(kit.cooldownEndBlock);
- siringWithId = uint256(kit.siringWithId);
- birthTime = uint256(kit.birthTime);
- matronId = uint256(kit.matronId);
- sireId = uint256(kit.sireId);
- generation = uint256(kit.generation);
- genes = kit.genes;
- }
-
- /// @dev Override unpause so it requires all external contract addresses
- /// to be set before contract can be unpaused. Also, we can't have
- /// newContractAddress set either, because then the contract was upgraded.
- /// @notice This is public rather than external so we can call super.unpause
- /// without using an expensive CALL.
- function unpause() public onlyCEO whenPaused {
- require(saleAuction != address(0));
- require(siringAuction != address(0));
- require(geneScience != address(0));
- require(newContractAddress == address(0));
-
- // Actually unpause the contract.
- super.unpause();
- }
-
- // @dev Allows the CFO to capture the balance available to the contract.
- function withdrawBalance() external onlyCFO {
- uint256 balance = this.balance;
- // Subtract all the currently pregnant kittens we have, plus 1 of margin.
- uint256 subtractFees = (pregnantKitties + 1) * autoBirthFee;
-
- if (balance > subtractFees) {
- cfoAddress.send(balance - subtractFees);
- }
- }
-}
diff --git a/example/errors/Contract113.sol b/example/errors/Contract113.sol
deleted file mode 100644
index 52ed3f7..0000000
--- a/example/errors/Contract113.sol
+++ /dev/null
@@ -1,638 +0,0 @@
-// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
-
-pragma solidity ^0.5.0;
-
-/**
- * @title Ownable
- * @dev The Ownable contract has an owner address, and provides basic authorization control
- * functions, this simplifies the implementation of "user permissions".
- */
-contract Ownable {
- address private _owner;
-
- event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-
- /**
- * @dev The Ownable constructor sets the original `owner` of the contract to the sender
- * account.
- */
- constructor () internal {
- _owner = msg.sender;
- emit OwnershipTransferred(address(0), _owner);
- }
-
- /**
- * @return the address of the owner.
- */
- function owner() public view returns (address) {
- return _owner;
- }
-
- /**
- * @dev Throws if called by any account other than the owner.
- */
- modifier onlyOwner() {
- require(isOwner());
- _;
- }
-
- /**
- * @return true if `msg.sender` is the owner of the contract.
- */
- function isOwner() public view returns (bool) {
- return msg.sender == _owner;
- }
-
- /**
- * @dev Allows the current owner to relinquish control of the contract.
- * @notice Renouncing to ownership will leave the contract without an owner.
- * It will not be possible to call the functions with the `onlyOwner`
- * modifier anymore.
- */
- function renounceOwnership() public onlyOwner {
- emit OwnershipTransferred(_owner, address(0));
- _owner = address(0);
- }
-
- /**
- * @dev Allows the current owner to transfer control of the contract to a newOwner.
- * @param newOwner The address to transfer ownership to.
- */
- function transferOwnership(address newOwner) public onlyOwner {
- _transferOwnership(newOwner);
- }
-
- /**
- * @dev Transfers control of the contract to a newOwner.
- * @param newOwner The address to transfer ownership to.
- */
- function _transferOwnership(address newOwner) internal {
- require(newOwner != address(0));
- emit OwnershipTransferred(_owner, newOwner);
- _owner = newOwner;
- }
-}
-
-// File: openzeppelin-solidity/contracts/math/SafeMath.sol
-
-pragma solidity ^0.5.0;
-
-/**
- * @title SafeMath
- * @dev Unsigned math operations with safety checks that revert on error
- */
-library SafeMath {
- /**
- * @dev Multiplies two unsigned integers, reverts on overflow.
- */
- function mul(uint256 a, uint256 b) internal pure returns (uint256) {
- // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
- // benefit is lost if 'b' is also tested.
- // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
- if (a == 0) {
- return 0;
- }
-
- uint256 c = a * b;
- require(c / a == b);
-
- return c;
- }
-
- /**
- * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
- */
- function div(uint256 a, uint256 b) internal pure returns (uint256) {
- // Solidity only automatically asserts when dividing by 0
- require(b > 0);
- uint256 c = a / b;
- // assert(a == b * c + a % b); // There is no case in which this doesn't hold
-
- return c;
- }
-
- /**
- * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
- */
- function sub(uint256 a, uint256 b) internal pure returns (uint256) {
- require(b <= a);
- uint256 c = a - b;
-
- return c;
- }
-
- /**
- * @dev Adds two unsigned integers, reverts on overflow.
- */
- function add(uint256 a, uint256 b) internal pure returns (uint256) {
- uint256 c = a + b;
- require(c >= a);
-
- return c;
- }
-
- /**
- * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
- * reverts when dividing by zero.
- */
- function mod(uint256 a, uint256 b) internal pure returns (uint256) {
- require(b != 0);
- return a % b;
- }
-}
-
-// File: openzeppelin-solidity/contracts/access/Roles.sol
-
-pragma solidity ^0.5.0;
-
-/**
- * @title Roles
- * @dev Library for managing addresses assigned to a Role.
- */
-library Roles {
- struct Role {
- mapping (address => bool) bearer;
- }
-
- /**
- * @dev give an account access to this role
- */
- function add(Role storage role, address account) internal {
- require(account != address(0));
- require(!has(role, account));
-
- role.bearer[account] = true;
- }
-
- /**
- * @dev remove an account's access to this role
- */
- function remove(Role storage role, address account) internal {
- require(account != address(0));
- require(has(role, account));
-
- role.bearer[account] = false;
- }
-
- /**
- * @dev check if an account has this role
- * @return bool
- */
- function has(Role storage role, address account) internal view returns (bool) {
- require(account != address(0));
- return role.bearer[account];
- }
-}
-
-// File: openzeppelin-solidity/contracts/access/roles/PauserRole.sol
-
-pragma solidity ^0.5.0;
-
-
-contract PauserRole {
- using Roles for Roles.Role;
-
- event PauserAdded(address indexed account);
- event PauserRemoved(address indexed account);
-
- Roles.Role private _pausers;
-
- constructor () internal {
- _addPauser(msg.sender);
- }
-
- modifier onlyPauser() {
- require(isPauser(msg.sender));
- _;
- }
-
- function isPauser(address account) public view returns (bool) {
- return _pausers.has(account);
- }
-
- function addPauser(address account) public onlyPauser {
- _addPauser(account);
- }
-
- function renouncePauser() public {
- _removePauser(msg.sender);
- }
-
- function _addPauser(address account) internal {
- _pausers.add(account);
- emit PauserAdded(account);
- }
-
- function _removePauser(address account) internal {
- _pausers.remove(account);
- emit PauserRemoved(account);
- }
-}
-
-// File: openzeppelin-solidity/contracts/lifecycle/Pausable.sol
-
-pragma solidity ^0.5.0;
-
-
-/**
- * @title Pausable
- * @dev Base contract which allows children to implement an emergency stop mechanism.
- */
-contract Pausable is PauserRole {
- event Paused(address account);
- event Unpaused(address account);
-
- bool private _paused;
-
- constructor () internal {
- _paused = false;
- }
-
- /**
- * @return true if the contract is paused, false otherwise.
- */
- function paused() public view returns (bool) {
- return _paused;
- }
-
- /**
- * @dev Modifier to make a function callable only when the contract is not paused.
- */
- modifier whenNotPaused() {
- require(!_paused);
- _;
- }
-
- /**
- * @dev Modifier to make a function callable only when the contract is paused.
- */
- modifier whenPaused() {
- require(_paused);
- _;
- }
-
- /**
- * @dev called by the owner to pause, triggers stopped state
- */
- function pause() public onlyPauser whenNotPaused {
- _paused = true;
- emit Paused(msg.sender);
- }
-
- /**
- * @dev called by the owner to unpause, returns to normal state
- */
- function unpause() public onlyPauser whenPaused {
- _paused = false;
- emit Unpaused(msg.sender);
- }
-}
-
-// File: contracts/libs/Strings.sol
-
-pragma solidity 0.5.0;
-
-library Strings {
-
- // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
- function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory _concatenatedString) {
- bytes memory _ba = bytes(_a);
- bytes memory _bb = bytes(_b);
- bytes memory _bc = bytes(_c);
- bytes memory _bd = bytes(_d);
- bytes memory _be = bytes(_e);
- string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
- bytes memory babcde = bytes(abcde);
- uint k = 0;
- uint i = 0;
- for (i = 0; i < _ba.length; i++) {
- babcde[k++] = _ba[i];
- }
- for (i = 0; i < _bb.length; i++) {
- babcde[k++] = _bb[i];
- }
- for (i = 0; i < _bc.length; i++) {
- babcde[k++] = _bc[i];
- }
- for (i = 0; i < _bd.length; i++) {
- babcde[k++] = _bd[i];
- }
- for (i = 0; i < _be.length; i++) {
- babcde[k++] = _be[i];
- }
- return string(babcde);
- }
-
- function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
- return strConcat(_a, _b, "", "", "");
- }
-
- function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
- return strConcat(_a, _b, _c, "", "");
- }
-
- function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
- if (_i == 0) {
- return "0";
- }
- uint j = _i;
- uint len;
- while (j != 0) {
- len++;
- j /= 10;
- }
- bytes memory bstr = new bytes(len);
- uint k = len - 1;
- while (_i != 0) {
- bstr[k--] = byte(uint8(48 + _i % 10));
- _i /= 10;
- }
- return string(bstr);
- }
-}
-
-// File: contracts/INiftyTradingCardCreator.sol
-
-pragma solidity 0.5.0;
-
-interface INiftyTradingCardCreator {
- function mintCard(
- uint256 _cardType,
- uint256 _nationality,
- uint256 _position,
- uint256 _ethnicity,
- uint256 _kit,
- uint256 _colour,
- address _to
- ) external returns (uint256 _tokenId);
-
- function setAttributes(
- uint256 _tokenId,
- uint256 _strength,
- uint256 _speed,
- uint256 _intelligence,
- uint256 _skill
- ) external returns (bool);
-
- function setName(
- uint256 _tokenId,
- uint256 _firstName,
- uint256 _lastName
- ) external returns (bool);
-
- function setAttributesAndName(
- uint256 _tokenId,
- uint256 _strength,
- uint256 _speed,
- uint256 _intelligence,
- uint256 _skill,
- uint256 _firstName,
- uint256 _lastName
- ) external returns (bool);
-}
-
-// File: contracts/generators/INiftyFootballTradingCardGenerator.sol
-
-pragma solidity 0.5.0;
-
-contract INiftyFootballTradingCardGenerator {
- function generateCard(address _sender) external returns (uint256 _nationality, uint256 _position, uint256 _ethnicity, uint256 _kit, uint256 _colour);
-
- function generateAttributes(address _sender, uint256 _base) external returns (uint256 strength, uint256 speed, uint256 intelligence, uint256 skill);
-
- function generateName(address _sender) external returns (uint256 firstName, uint256 lastName);
-}
-
-// File: contracts/FundsSplitter.sol
-
-pragma solidity ^0.5.0;
-
-
-
-contract FundsSplitter is Ownable {
- using SafeMath for uint256;
-
- address payable public platform;
- address payable public partner;
-
- uint256 public partnerRate = 7;
-
- constructor (address payable _platform, address payable _partner) public {
- platform = _platform;
- partner = _partner;
- }
-
- function splitFunds(uint256 _totalPrice) internal {
- if (msg.value > 0) {
- uint256 refund = msg.value.sub(_totalPrice);
-
- // overpaid...
- if (refund > 0) {
- msg.sender.transfer(refund);
- }
-
- // work out the amount to split and send it
- uint256 partnerAmount = _totalPrice.div(100).mul(partnerRate);
- partner.transfer(partnerAmount);
-
- // send remaining amount to partner wallet
- uint256 remaining = _totalPrice.sub(partnerAmount);
- platform.transfer(remaining);
- }
- }
-
- function updatePartnerAddress(address payable _partner) onlyOwner public {
- partner = _partner;
- }
-
- function updatePartnerRate(uint256 _techPartnerRate) onlyOwner public {
- partnerRate = _techPartnerRate;
- }
-
- function updatePlatformAddress(address payable _platform) onlyOwner public {
- platform = _platform;
- }
-
- function withdraw() public onlyOwner returns (bool) {
- platform.transfer(address(this).balance);
- return true;
- }
-}
-
-// File: contracts/NiftyFootballTradingCardEliteBlindPack.sol
-
-pragma solidity 0.5.0;
-
-
-
-
-
-
-
-
-
-contract NiftyFootballTradingCardEliteBlindPack is Ownable, Pausable, FundsSplitter {
- using SafeMath for uint256;
-
- event PriceInWeiChanged(uint256 _old, uint256 _new);
-
- event DefaultCardTypeChanged(uint256 _new);
-
- event AttributesBaseChanged(uint256 _new);
-
- event FutballCardsGeneratorChanged(INiftyFootballTradingCardGenerator _new);
-
- INiftyFootballTradingCardGenerator public generator;
- INiftyTradingCardCreator public creator;
-
- uint256 public totalPurchasesInWei = 0;
- uint256 public cardTypeDefault = 0;
- uint256 public attributesBase = 60; // Standard 60-100
-
- uint256[] public pricePerCard = [
- // single cards
- 16000000000000000, // 1 @ = 0.016 ETH / $2.50
- 16000000000000000, // 2 @ = 0.016 ETH / $2.50
-
- // 1 packs
- 14500000000000000, // 3 @ = 0.0145 ETH / $2.30
- 14500000000000000, // 4 @ = 0.0145 ETH / $2.30
- 14500000000000000, // 5 @ = 0.0145 ETH / $2.30
-
- // 2 packs
- 13500000000000000, // 6 @ = 0.0135 ETH / $2.15
- 13500000000000000, // 7 @ = 0.0135 ETH / $2.15
- 13500000000000000, // 8 @ = 0.0135 ETH / $2.15
-
- // 3 packs or more
- 12500000000000000, // 9 @ = 0.0125 ETH / $2
- 12500000000000000 // 10 @ = 0.0125 ETH / $2
- ];
-
- constructor (
- address payable _wallet,
- address payable _partnerAddress,
- INiftyFootballTradingCardGenerator _generator,
- INiftyTradingCardCreator _creator
- ) public FundsSplitter(_wallet, _partnerAddress) {
- generator = _generator;
- creator = _creator;
- }
-
- function blindPack() whenNotPaused public payable {
- blindPackTo(msg.sender);
- }
-
- function blindPackTo(address _to) whenNotPaused public payable {
- uint256 _totalPrice = totalPrice(1);
- require(
- msg.value >= _totalPrice,
- "Must supply at least the required minimum purchase value"
- );
- require(!isContract(msg.sender), "Unable to buy packs from another contract");
-
- _generateAndAssignCard(_to);
-
- _takePayment(1, _totalPrice);
- }
-
- function buyBatch(uint256 _numberOfCards) whenNotPaused public payable {
- return buyBatchTo(msg.sender, _numberOfCards);
- }
-
- function buyBatchTo(address _to, uint256 _numberOfCards) whenNotPaused public payable {
- uint256 _totalPrice = totalPrice(_numberOfCards);
- require(
- msg.value >= _totalPrice,
- "Must supply at least the required minimum purchase value"
- );
- require(!isContract(msg.sender), "Unable to buy packs from another contract");
-
- for (uint i = 0; i < _numberOfCards; i++) {
- _generateAndAssignCard(_to);
- }
-
- _takePayment(_numberOfCards, _totalPrice);
- }
-
- function _generateAndAssignCard(address _to) internal {
- // Generate card
- (uint256 _nationality, uint256 _position, uint256 _ethnicity, uint256 _kit, uint256 _colour) = generator.generateCard(msg.sender);
-
- // cardType is 0 for genesis (initially)
- uint256 tokenId = creator.mintCard(cardTypeDefault, _nationality, _position, _ethnicity, _kit, _colour, _to);
-
- // Generate attributes
- (uint256 _strength, uint256 _speed, uint256 _intelligence, uint256 _skill) = generator.generateAttributes(msg.sender, attributesBase);
- (uint256 _firstName, uint256 _lastName) = generator.generateName(msg.sender);
-
- creator.setAttributesAndName(tokenId, _strength, _speed, _intelligence, _skill, _firstName, _lastName);
- }
-
- function _takePayment(uint256 _numberOfCards, uint256 _totalPrice) internal {
- // any trapped ether can be withdrawn with withdraw()
- totalPurchasesInWei = totalPurchasesInWei.add(_totalPrice);
- splitFunds(_totalPrice);
- }
-
- function setCardTypeDefault(uint256 _newDefaultCardType) public onlyOwner returns (bool) {
- cardTypeDefault = _newDefaultCardType;
-
- emit DefaultCardTypeChanged(_newDefaultCardType);
-
- return true;
- }
-
- function setAttributesBase(uint256 _newAttributesBase) public onlyOwner returns (bool) {
- attributesBase = _newAttributesBase;
-
- emit AttributesBaseChanged(_newAttributesBase);
-
- return true;
- }
-
- function setFutballCardsGenerator(INiftyFootballTradingCardGenerator _futballCardsGenerator) public onlyOwner returns (bool) {
- generator = _futballCardsGenerator;
-
- emit FutballCardsGeneratorChanged(_futballCardsGenerator);
-
- return true;
- }
-
- function updatePricePerCardAtIndex(uint256 _index, uint256 _priceInWei) public onlyOwner returns (bool) {
- pricePerCard[_index] = _priceInWei;
- return true;
- }
-
- function updatePricePerCard(uint256[] memory _pricePerCard) public onlyOwner returns (bool) {
- pricePerCard = _pricePerCard;
- return true;
- }
-
- function totalPrice(uint256 _numberOfCards) public view returns (uint256) {
- if (_numberOfCards > pricePerCard.length) {
- return pricePerCard[pricePerCard.length - 1].mul(_numberOfCards);
- }
- return pricePerCard[_numberOfCards - 1].mul(_numberOfCards);
- }
-
- /**
- * Returns whether the target address is a contract
- * Based on OpenZeppelin Address library
- * @dev This function will return false if invoked during the constructor of a contract,
- * as the code is not actually created until after the constructor finishes.
- * @param account address of the account to check
- * @return whether the target address is a contract
- */
- function isContract(address account) internal view returns (bool) {
- uint256 size;
- // XXX Currently there is no better way to check if there is a contract in an address
- // than to check the size of the code at that address.
- // See https://ethereum.stackexchange.com/a/14016/36603
- // for more details about how this works.
- // contracts then.
- // solhint-disable-next-line no-inline-assembly
- assembly {size := extcodesize(account)}
- return size > 0;
- }
-}
\ No newline at end of file
diff --git a/example/errors/Contract120.sol b/example/errors/Contract120.sol
deleted file mode 100644
index d614472..0000000
--- a/example/errors/Contract120.sol
+++ /dev/null
@@ -1,649 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-only
-pragma solidity 0.7.6;
-pragma abicoder v2;
-
-import {SafeMath} from "@openzeppelin/contracts/math/SafeMath.sol";
-import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
-
-import {IERC721} from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
-import {IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
-
-import {Initializable} from "@openzeppelin/contracts/proxy/Initializable.sol";
-import {EnumerableSet} from "@openzeppelin/contracts/utils/EnumerableSet.sol";
-import {Address} from "@openzeppelin/contracts/utils/Address.sol";
-import {TransferHelper} from "@uniswap/lib/contracts/libraries/TransferHelper.sol";
-
-import {EIP712} from "./EIP712.sol";
-import {ERC1271} from "./ERC1271.sol";
-import {OwnableERC721} from "./OwnableERC721.sol";
-import {IRageQuit} from "../hypervisor/Hypervisor.sol";
-
-import {IUniversalVault} from "../interfaces/IUniversalVault.sol";
-import {IVisorService} from "../interfaces/IVisorService.sol";
-
-/// @title Visor
-/// @notice Vault for isolated storage of staking tokens
-/// @dev Warning: not compatible with rebasing tokens
-contract Visor is
- IUniversalVault,
- EIP712("UniversalVault", "1.0.0"),
- ERC1271,
- OwnableERC721,
- Initializable,
- IERC721Receiver
-{
- using SafeMath for uint256;
- using Address for address;
- using Address for address payable;
- using EnumerableSet for EnumerableSet.Bytes32Set;
-
- /* constant */
-
- // Hardcoding a gas limit for rageQuit() is required to prevent gas DOS attacks
- // the gas requirement cannot be determined at runtime by querying the delegate
- // as it could potentially be manipulated by a malicious delegate who could force
- // the calls to revert.
- // The gas limit could alternatively be set upon vault initialization or creation
- // of a lock, but the gas consumption trade-offs are not favorable.
- // Ultimately, to avoid a need for fixed gas limits, the EVM would need to provide
- // an error code that allows for reliably catching out-of-gas errors on remote calls.
- uint256 public constant RAGEQUIT_GAS = 500000;
- bytes32 public constant LOCK_TYPEHASH =
- keccak256("Lock(address delegate,address token,uint256 amount,uint256 nonce)");
- bytes32 public constant UNLOCK_TYPEHASH =
- keccak256("Unlock(address delegate,address token,uint256 amount,uint256 nonce)");
-
- string public constant VERSION = "VISOR-2.0.5";
-
- /* storage */
-
- string public uri;
- uint256 private _nonce;
- mapping(bytes32 => LockData) private _locks;
- EnumerableSet.Bytes32Set private _lockSet;
-
- struct Nft {
- uint256 tokenId;
- address nftContract;
- }
-
- mapping(bytes32 => Nft) private _nfts;
- EnumerableSet.Bytes32Set private _nftSet;
-
- mapping(bytes32=>bool) public nftApprovals;
- mapping(bytes32=>uint256) public erc20Approvals;
-
- struct TimelockERC20 {
- address recipient;
- address token;
- uint256 amount;
- uint256 expires;
- }
-
- mapping(bytes32=>TimelockERC20) public timelockERC20s;
- mapping(address=>EnumerableSet.Bytes32Set) private timelockERC20Keys;
- mapping(address=>uint256) public timelockERC20Balances;
-
- struct TimelockERC721 {
- address recipient;
- address nftContract;
- uint256 tokenId;
- uint256 expires;
- }
-
- mapping(bytes32=>TimelockERC721) public timelockERC721s;
- mapping(address=>EnumerableSet.Bytes32Set) private timelockERC721Keys;
-
- event AddNftToken(address nftContract, uint256 tokenId);
- event RemoveNftToken(address nftContract, uint256 tokenId);
- event TimeLockERC20(address recipient, address token, uint256 amount, uint256 expires);
- event TimeUnlockERC20(address recipient, address token, uint256 amount, uint256 expires);
- event TimeLockERC721(address recipient, address nftContract, uint256 tokenId, uint256 expires);
- event TimeUnlockERC721(address recipient, address nftContract, uint256 tokenId, uint256 expires);
-
- /* initialization function */
-
- function initializeLock() external initializer {}
-
- function initialize() external override initializer {
- OwnableERC721._setNFT(msg.sender);
- }
-
- /* ether receive */
-
- receive() external payable {}
-
- /* internal */
-
- function _addNft(address nftContract, uint256 tokenId) internal {
-
- bytes32 key = calculateNftID(nftContract, tokenId);
- // add nft to set
- assert(_nftSet.add(key));
- // add nft data to storage
- _nfts[key] = Nft(tokenId, nftContract);
- emit AddNftToken(nftContract, tokenId);
- }
-
- function _removeNft(address nftContract, uint256 tokenId) internal {
- bytes32 key = calculateNftID(nftContract, tokenId);
- // update nft storage
- assert(_nftSet.remove(key));
- delete _nfts[key];
- emit RemoveNftToken(nftContract, tokenId);
- }
-
- function setURI(string memory _uri) public onlyOwner {
- uri = _uri;
- }
-
- function _getOwner() internal view override(ERC1271) returns (address ownerAddress) {
- return OwnableERC721.owner();
- }
-
- /* pure functions */
-
- function calculateLockID(address delegate, address token)
- public
- pure
- override
- returns (bytes32 lockID)
- {
- return keccak256(abi.encodePacked(delegate, token));
- }
-
- function calculateNftID(address nftContract, uint256 tokenId)
- public
- pure
- returns (bytes32 nftId)
- {
- return keccak256(abi.encodePacked(nftContract, tokenId));
- }
-
- /* getter functions */
-
- function getPermissionHash(
- bytes32 eip712TypeHash,
- address delegate,
- address token,
- uint256 amount,
- uint256 nonce
- ) public view override returns (bytes32 permissionHash) {
- return
- EIP712._hashTypedDataV4(
- keccak256(abi.encode(eip712TypeHash, delegate, token, amount, nonce))
- );
- }
-
- function getNonce() external view override returns (uint256 nonce) {
- return _nonce;
- }
-
- function owner()
- public
- view
- override(IUniversalVault, OwnableERC721)
- returns (address ownerAddress)
- {
- return OwnableERC721.owner();
- }
-
- function getLockSetCount() external view override returns (uint256 count) {
- return _lockSet.length();
- }
-
- function getLockAt(uint256 index) external view override returns (LockData memory lockData) {
- return _locks[_lockSet.at(index)];
- }
-
- function getBalanceDelegated(address token, address delegate)
- external
- view
- override
- returns (uint256 balance)
- {
- return _locks[calculateLockID(delegate, token)].balance;
- }
-
- function getBalanceLocked(address token) public view override returns (uint256 balance) {
- uint256 count = _lockSet.length();
- for (uint256 index; index < count; index++) {
- LockData storage _lockData = _locks[_lockSet.at(index)];
- if (_lockData.token == token && _lockData.balance > balance)
- balance = _lockData.balance;
- }
- return balance;
- }
-
- function checkBalances() external view override returns (bool validity) {
- // iterate over all token locks and validate sufficient balance
- uint256 count = _lockSet.length();
- for (uint256 index; index < count; index++) {
- // fetch storage lock reference
- LockData storage _lockData = _locks[_lockSet.at(index)];
- // if insufficient balance and no∏t shutdown, return false
- if (IERC20(_lockData.token).balanceOf(address(this)) < _lockData.balance) return false;
- }
- // if sufficient balance or shutdown, return true
- return true;
- }
-
- // @notice Get ERC721 from nfts[] by index
- /// @param index nfts index of nfts[]
- function getNFTByIndex(uint256 index) external view returns (Nft memory nftData) {
- require(index < _nftSet.length(), "ID overflow");
- return _nfts[_nftSet.at(index)];
- }
-
- // @notice Get number of timelocks for given ERC20 token
- function getTimeLockCount(address token) external view returns(uint256) {
- return timelockERC20Keys[token].length();
- }
-
- // @notice Get number of timelocks for NFTs of a given ERC721 contract
- function getTimeLockERC721Count(address nftContract) external view returns(uint256) {
- return timelockERC721Keys[nftContract].length();
- }
-
- /* user functions */
-
- /// @notice Lock ERC20 tokens in the vault
- /// access control: called by delegate with signed permission from owner
- /// state machine: anytime
- /// state scope:
- /// - insert or update _locks
- /// - increase _nonce
- /// token transfer: none
- /// @param token Address of token being locked
- /// @param amount Amount of tokens being locked
- /// @param permission Permission signature payload
- function lock(
- address token,
- uint256 amount,
- bytes calldata permission
- )
- external
- override
- onlyValidSignature(
- getPermissionHash(LOCK_TYPEHASH, msg.sender, token, amount, _nonce),
- permission
- )
- {
- // get lock id
- bytes32 lockID = calculateLockID(msg.sender, token);
-
- // add lock to storage
- if (_lockSet.contains(lockID)) {
- // if lock already exists, increase amount
- _locks[lockID].balance = _locks[lockID].balance.add(amount);
- } else {
- // if does not exist, create new lock
- // add lock to set
- assert(_lockSet.add(lockID));
- // add lock data to storage
- _locks[lockID] = LockData(msg.sender, token, amount);
- }
-
- // validate sufficient balance
- require(
- IERC20(token).balanceOf(address(this)) >= _locks[lockID].balance,
- "UniversalVault: insufficient balance"
- );
-
- // increase nonce
- _nonce += 1;
-
- // emit event
- emit Locked(msg.sender, token, amount);
- }
-
- /// @notice Unlock ERC20 tokens in the vault
- /// access control: called by delegate with signed permission from owner
- /// state machine: after valid lock from delegate
- /// state scope:
- /// - remove or update _locks
- /// - increase _nonce
- /// token transfer: none
- /// @param token Address of token being unlocked
- /// @param amount Amount of tokens being unlocked
- /// @param permission Permission signature payload
- function unlock(
- address token,
- uint256 amount,
- bytes calldata permission
- )
- external
- override
- onlyValidSignature(
- getPermissionHash(UNLOCK_TYPEHASH, msg.sender, token, amount, _nonce),
- permission
- )
- {
- // get lock id
- bytes32 lockID = calculateLockID(msg.sender, token);
-
- // validate existing lock
- require(_lockSet.contains(lockID), "UniversalVault: missing lock");
-
- // update lock data
- if (_locks[lockID].balance > amount) {
- // substract amount from lock balance
- _locks[lockID].balance = _locks[lockID].balance.sub(amount);
- } else {
- // delete lock data
- delete _locks[lockID];
- assert(_lockSet.remove(lockID));
- }
-
- // increase nonce
- _nonce += 1;
-
- // emit event
- emit Unlocked(msg.sender, token, amount);
- }
-
- /// @notice Forcibly cancel delegate lock
- /// @dev This function will attempt to notify the delegate of the rage quit using
- /// a fixed amount of gas.
- /// access control: only owner
- /// state machine: after valid lock from delegate
- /// state scope:
- /// - remove item from _locks
- /// token transfer: none
- /// @param delegate Address of delegate
- /// @param token Address of token being unlocked
- function rageQuit(address delegate, address token)
- external
- override
- onlyOwner
- returns (bool notified, string memory error)
- {
- // get lock id
- bytes32 lockID = calculateLockID(delegate, token);
-
- // validate existing lock
- require(_lockSet.contains(lockID), "UniversalVault: missing lock");
-
- // attempt to notify delegate
- if (delegate.isContract()) {
- // check for sufficient gas
- require(gasleft() >= RAGEQUIT_GAS, "UniversalVault: insufficient gas");
-
- // attempt rageQuit notification
- try IRageQuit(delegate).rageQuit{gas: RAGEQUIT_GAS}() {
- notified = true;
- } catch Error(string memory res) {
- notified = false;
- error = res;
- } catch (bytes memory) {
- notified = false;
- }
- }
-
- // update lock storage
- assert(_lockSet.remove(lockID));
- delete _locks[lockID];
-
- // emit event
- emit RageQuit(delegate, token, notified, error);
- }
-
- /// @notice Transfer ERC20 tokens out of vault
- /// access control: only owner
- /// state machine: when balance >= max(lock) + amount
- /// state scope: none
- /// token transfer: transfer any token
- /// @param token Address of token being transferred
- /// @param to Address of the to
- /// @param amount Amount of tokens to transfer
- function transferERC20(
- address token,
- address to,
- uint256 amount
- ) external override onlyOwner {
- // check for sufficient balance
- require(
- IERC20(token).balanceOf(address(this)) >= (getBalanceLocked(token).add(amount)).add(timelockERC20Balances[token]),
- "UniversalVault: insufficient balance"
- );
- // perform transfer
- TransferHelper.safeTransfer(token, to, amount);
- }
-
- // @notice Approve delegate account to transfer ERC20 tokens out of vault
- /// @param token Address of token being transferred
- /// @param delegate Address being approved
- /// @param amount Amount of tokens approved to transfer
- function approveTransferERC20(address token, address delegate, uint256 amount) external onlyOwner {
- erc20Approvals[keccak256(abi.encodePacked(delegate, token))] = amount;
- }
-
- /// @notice Transfer ERC20 tokens out of vault with an approved account
- /// access control: only approved accounts in erc20Approvals
- /// state machine: when balance >= max(lock) + amount
- /// state scope: none
- /// token transfer: transfer any token
- /// @param token Address of token being transferred
- /// @param to Address of the to
- /// @param amount Amount of tokens to transfer
- function delegatedTransferERC20(
- address token,
- address to,
- uint256 amount
- ) external {
-
- bytes32 key = keccak256(abi.encodePacked(msg.sender, token));
- // check for sufficient balance
- require(
- IERC20(token).balanceOf(address(this)) >= (getBalanceLocked(token).add(amount)).add(timelockERC20Balances[token]),
- "UniversalVault: insufficient balance"
- );
- erc20Approvals[key] = erc20Approvals[key].sub(amount);
-
- // perform transfer
- TransferHelper.safeTransfer(token, to, amount);
- }
-
- /// @notice Transfer ETH out of vault
- /// access control: only owner
- /// state machine: when balance >= amount
- /// state scope: none
- /// token transfer: transfer any token
- /// @param to Address of the to
- /// @param amount Amount of ETH to transfer
- function transferETH(address to, uint256 amount) external payable override onlyOwner {
- // perform transfer
- TransferHelper.safeTransferETH(to, amount);
- }
-
- // @notice Approve delegate account to transfer ERC721 token out of vault
- /// @param delegate Account address being approved to transfer nft
- /// @param nftContract address of nft minter
- /// @param tokenId token id of the nft instance
- /// @param approved approval boolean value
- function approveTransferERC721(
- address delegate,
- address nftContract,
- uint256 tokenId,
- bool approved
- ) external onlyOwner {
- nftApprovals[keccak256(abi.encodePacked(delegate, nftContract, tokenId))] = approved;
- }
-
- /// @notice Transfer ERC721 out of vault
- /// access control: only owner or approved
- /// ERC721 transfer: transfer any ERC721 token
- /// @param to recipient address
- /// @param nftContract address of nft minter
- /// @param tokenId token id of the nft instance
- function transferERC721(
- address to,
- address nftContract,
- uint256 tokenId
- ) external {
- if(msg.sender != _getOwner()) {
- bytes32 key = keccak256(abi.encodePacked(msg.sender, nftContract, tokenId));
- require( nftApprovals[key], "NFT not approved for transfer");
- nftApprovals[key] = false;
- }
-
- for(uint256 i=0; i block.timestamp,
- "Expires must be in future"
- );
-
- bytes32 key = keccak256(abi.encodePacked(recipient, nftContract, tokenId, expires));
-
- require(
- timelockERC721s[key].expires == 0,
- "TimelockERC721 already exists"
- );
-
- timelockERC721s[key] = TimelockERC721({
- recipient: recipient,
- nftContract: nftContract,
- tokenId: tokenId,
- expires: expires
- });
-
- timelockERC721Keys[nftContract].add(key);
-
- IERC721(nftContract).safeTransferFrom(msg.sender, address(this), tokenId);
- emit TimeLockERC721(recipient, nftContract, tokenId, expires);
- }
-
- // @notice Withdraw ERC721 in vault post expires by recipient
- /// @param recipient Address with right to withdraw after expires
- /// @param nftContract address of nft minter
- /// @param tokenId Token id of the nft instance
- /// @param expires Timestamp when recipient is allowed to withdraw
- function timeUnlockERC721(address recipient, address nftContract, uint256 tokenId, uint256 expires) external {
-
- bytes32 key = keccak256(abi.encodePacked(recipient, nftContract, tokenId, expires));
- require(
- timelockERC721s[key].expires <= block.timestamp,
- "Not expired yet"
- );
-
- require(msg.sender == timelockERC721s[key].recipient, "Not recipient");
-
- _removeNft(nftContract, tokenId);
- delete timelockERC721s[key];
- timelockERC721Keys[nftContract].remove(key);
-
- IERC721(nftContract).safeTransferFrom(address(this), recipient, tokenId);
- emit TimeUnlockERC721(recipient, nftContract, tokenId, expires);
- }
-
- // @notice Lock ERC720 amount in vault until expires, redeemable by recipient
- /// @param recipient Address with right to withdraw after expires
- /// @param token Address of token to lock
- /// @param amount Amount of token to lock
- /// @param expires Timestamp when recipient is allowed to withdraw
- function timeLockERC20(address recipient, address token, uint256 amount, uint256 expires) external onlyOwner {
-
- require(
- IERC20(token).allowance(msg.sender, address(this)) >= amount,
- "Amount not approved"
- );
-
- require(
- expires > block.timestamp,
- "Expires must be in future"
- );
-
- bytes32 key = keccak256(abi.encodePacked(recipient, token, amount, expires));
-
- require(
- timelockERC20s[key].expires == 0,
- "TimelockERC20 already exists"
- );
-
- timelockERC20s[key] = TimelockERC20({
- recipient: recipient,
- token: token,
- amount: amount,
- expires: expires
- });
- timelockERC20Keys[token].add(key);
- timelockERC20Balances[token] = timelockERC20Balances[token].add(amount);
- TransferHelper.safeTransferFrom(token, msg.sender, address(this), amount);
- emit TimeLockERC20(recipient, token, amount, expires);
- }
-
- // @notice Withdraw ERC20 from vault post expires by recipient
- /// @param recipient Address with right to withdraw after expires
- /// @param token Address of token to lock
- /// @param amount Amount of token to lock
- /// @param expires Timestamp when recipient is allowed to withdraw
- function timeUnlockERC20(address recipient, address token, uint256 amount, uint256 expires) external {
-
- require(
- IERC20(token).balanceOf(address(this)) >= getBalanceLocked(token).add(amount),
- "Insufficient balance"
- );
-
- bytes32 key = keccak256(abi.encodePacked(recipient, token, amount, expires));
- require(
- timelockERC20s[key].expires <= block.timestamp,
- "Not expired yet"
- );
-
- require(msg.sender == timelockERC20s[key].recipient, "Not recipient");
-
- delete timelockERC20s[key];
- timelockERC20Keys[token].remove(key);
-
- timelockERC20Balances[token] = timelockERC20Balances[token].sub(amount);
- TransferHelper.safeTransfer(token, recipient, amount);
- emit TimeUnlockERC20(recipient, token, amount, expires);
- }
-
- // @notice get timelockERC20Key by address and index
- /// @param token Address of token
- /// @param index index of keys Bytes32Set
- function getTimelockERC20Key(address token, uint256 index) external returns(bytes32) {
- require(timelockERC20Keys[token].length() > 0 && timelockERC20Keys[token].length() > index, "Index should be smaller than count");
- return timelockERC20Keys[token].at(index);
- }
-
- // @notice get timelockERC721Key by address and index
- /// @param nftContract Address of token
- /// @param index index of keys Bytes32Set
- function getTimelockERC721Key(address nftContract, uint256 index) external returns(bytes32) {
- require(timelockERC721Keys[nftContract].length() > 0 && timelockERC721Keys[nftContract].length() > index, "Index should be smaller than count");
- return timelockERC721Keys[nftContract].at(index);
- }
-}
diff --git a/example/errors/Contract1584.sol b/example/errors/Contract1584.sol
deleted file mode 100644
index 73a6157..0000000
--- a/example/errors/Contract1584.sol
+++ /dev/null
@@ -1,1452 +0,0 @@
-/**
- *Submitted for verification at Etherscan.io on 2021-08-26
-*/
-
-// File: contracts/ERC721/ERC721ReceiverDraft.sol
-
-pragma solidity ^0.5.10;
-
-
-/// @title ERC721ReceiverDraft
-/// @dev Interface for any contract that wants to support safeTransfers from
-/// ERC721 asset contracts.
-/// @dev Note: this is the interface defined from
-/// https://github.com/ethereum/EIPs/commit/2bddd126def7c046e1e62408dc2b51bdd9e57f0f
-/// to https://github.com/ethereum/EIPs/commit/27788131d5975daacbab607076f2ee04624f9dbb
-/// and is not the final interface.
-/// Due to the extended period of time this revision was specified in the draft,
-/// we are supporting both this and the newer (final) interface in order to be
-/// compatible with any ERC721 implementations that may have used this interface.
-contract ERC721ReceiverDraft {
-
- /// @dev Magic value to be returned upon successful reception of an NFT
- /// Equals to `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`,
- /// which can be also obtained as `ERC721ReceiverDraft(0).onERC721Received.selector`
- /// @dev see https://github.com/ethereum/EIPs/commit/2bddd126def7c046e1e62408dc2b51bdd9e57f0f
- bytes4 internal constant ERC721_RECEIVED_DRAFT = 0xf0b9e5ba;
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. This function MUST use 50,000 gas or less. Return of other
- /// than the magic value MUST result in the transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _from The sending address
- /// @param _tokenId The NFT identifier which is being transfered
- /// @param data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(address _from, uint256 _tokenId, bytes calldata data) external returns(bytes4);
-}
-
-// File: contracts/ERC721/ERC721ReceiverFinal.sol
-
-pragma solidity ^0.5.10;
-
-
-/// @title ERC721ReceiverFinal
-/// @notice Interface for any contract that wants to support safeTransfers from
-/// ERC721 asset contracts.
-/// @dev Note: this is the final interface as defined at http://erc721.org
-contract ERC721ReceiverFinal {
-
- /// @dev Magic value to be returned upon successful reception of an NFT
- /// Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`,
- /// which can be also obtained as `ERC721ReceiverFinal(0).onERC721Received.selector`
- /// @dev see https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v1.12.0/contracts/token/ERC721/ERC721Receiver.sol
- bytes4 internal constant ERC721_RECEIVED_FINAL = 0x150b7a02;
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `safetransfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes memory _data
- )
- public
- returns (bytes4);
-}
-
-// File: contracts/ERC721/ERC721Receivable.sol
-
-pragma solidity ^0.5.10;
-
-
-
-/// @title ERC721Receivable handles the reception of ERC721 tokens
-/// See ERC721 specification
-/// @author Christopher Scott
-/// @dev These functions are public, and could be called by anyone, even in the case
-/// where no NFTs have been transferred. Since it's not a reliable source of
-/// truth about ERC721 tokens being transferred, we save the gas and don't
-/// bother emitting a (potentially spurious) event as found in
-/// https://github.com/OpenZeppelin/openzeppelin-solidity/blob/5471fc808a17342d738853d7bf3e9e5ef3108074/contracts/mocks/ERC721ReceiverMock.sol
-contract ERC721Receivable is ERC721ReceiverDraft, ERC721ReceiverFinal {
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `transfer`. This function MAY throw to revert and reject the
- /// transfer. This function MUST use 50,000 gas or less. Return of other
- /// than the magic value MUST result in the transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _from The sending address
- /// @param _tokenId The NFT identifier which is being transfered
- /// @param data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
- /// unless throwing
- function onERC721Received(address _from, uint256 _tokenId, bytes calldata data) external returns(bytes4) {
- _from;
- _tokenId;
- data;
-
- // emit ERC721Received(_operator, _from, _tokenId, _data, gasleft());
-
- return ERC721_RECEIVED_DRAFT;
- }
-
- /// @notice Handle the receipt of an NFT
- /// @dev The ERC721 smart contract calls this function on the recipient
- /// after a `safetransfer`. This function MAY throw to revert and reject the
- /// transfer. Return of other than the magic value MUST result in the
- /// transaction being reverted.
- /// Note: the contract address is always the message sender.
- /// @param _operator The address which called `safeTransferFrom` function
- /// @param _from The address which previously owned the token
- /// @param _tokenId The NFT identifier which is being transferred
- /// @param _data Additional data with no specified format
- /// @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
- function onERC721Received(
- address _operator,
- address _from,
- uint256 _tokenId,
- bytes memory _data
- )
- public
- returns(bytes4)
- {
- _operator;
- _from;
- _tokenId;
- _data;
-
- // emit ERC721Received(_operator, _from, _tokenId, _data, gasleft());
-
- return ERC721_RECEIVED_FINAL;
- }
-
-}
-
-// File: contracts/ERC223/ERC223Receiver.sol
-
-pragma solidity ^0.5.10;
-
-
-/// @title ERC223Receiver ensures we are ERC223 compatible
-/// @author Christopher Scott
-contract ERC223Receiver {
-
- bytes4 public constant ERC223_ID = 0xc0ee0b8a;
-
- struct TKN {
- address sender;
- uint value;
- bytes data;
- bytes4 sig;
- }
-
- /// @notice tokenFallback is called from an ERC223 compatible contract
- /// @param _from the address from which the token was sent
- /// @param _value the amount of tokens sent
- /// @param _data the data sent with the transaction
- function tokenFallback(address _from, uint _value, bytes memory _data) public pure {
- _from;
- _value;
- _data;
- // TKN memory tkn;
- // tkn.sender = _from;
- // tkn.value = _value;
- // tkn.data = _data;
- // uint32 u = uint32(_data[3]) + (uint32(_data[2]) << 8) + (uint32(_data[1]) << 16) + (uint32(_data[0]) << 24);
- // tkn.sig = bytes4(u);
-
- /* tkn variable is analogue of msg variable of Ether transaction
- * tkn.sender is person who initiated this token transaction (analogue of msg.sender)
- * tkn.value the number of tokens that were sent (analogue of msg.value)
- * tkn.data is data of token transaction (analogue of msg.data)
- * tkn.sig is 4 bytes signature of function
- * if data of token transaction is a function execution
- */
-
- }
-}
-
-// File: contracts/ERC1155/ERC1155TokenReceiver.sol
-
-pragma solidity ^0.5.10;
-
-contract ERC1155TokenReceiver {
- /// @dev `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)")) ^
- /// bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
- bytes4 internal constant ERC1155_TOKEN_RECIEVER = 0x4e2312e0;
-
- /**
- @notice Handle the receipt of a single ERC1155 token type.
- @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeTransferFrom` after the balance has been updated.
- This function MUST return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (i.e. 0xf23a6e61) if it accepts the transfer.
- This function MUST revert if it rejects the transfer.
- Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
- @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)"))`
- */
- function onERC1155Received(
- address _operator,
- address _from,
- uint256 _id,
- uint256 _value,
- bytes calldata _data
- ) external pure returns (bytes4) {
- _operator;
- _from;
- _id;
- _value;
- _data;
-
- return 0xf23a6e61;
- }
-
- /**
- @notice Handle the receipt of multiple ERC1155 token types.
- @dev An ERC1155-compliant smart contract MUST call this function on the token recipient contract, at the end of a `safeBatchTransferFrom` after the balances have been updated.
- This function MUST return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (i.e. 0xbc197c81) if it accepts the transfer(s).
- This function MUST revert if it rejects the transfer(s).
- Return of any other value than the prescribed keccak256 generated value MUST result in the transaction being reverted by the caller.
- @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)"))`
- */
- function onERC1155BatchReceived(
- address _operator,
- address _from,
- uint256[] calldata _ids,
- uint256[] calldata _values,
- bytes calldata _data
- ) external pure returns (bytes4) {
- _operator;
- _from;
- _ids;
- _values;
- _data;
-
- return 0xbc197c81;
- }
-}
-
-// File: contracts/ERC1271/ERC1271.sol
-
-pragma solidity ^0.5.10;
-
-contract ERC1271 {
-
- /// @dev bytes4(keccak256("isValidSignature(bytes32,bytes)")
- bytes4 internal constant ERC1271_VALIDSIGNATURE = 0x1626ba7e;
-
- /// @dev Should return whether the signature provided is valid for the provided data
- /// @param hash 32-byte hash of the data that is signed
- /// @param _signature Signature byte array associated with _data
- /// MUST return the bytes4 magic value 0x1626ba7e when function passes.
- /// MUST NOT modify state (using STATICCALL for solc < 0.5, view modifier for solc > 0.5)
- /// MUST allow external calls
- function isValidSignature(
- bytes32 hash,
- bytes calldata _signature)
- external
- view
- returns (bytes4);
-}
-
-// File: contracts/ECDSA.sol
-
-pragma solidity ^0.5.10;
-
-
-/// @title ECDSA is a library that contains useful methods for working with ECDSA signatures
-library ECDSA {
-
- /// @notice Extracts the r, s, and v components from the `sigData` field starting from the `offset`
- /// @dev Note: does not do any bounds checking on the arguments!
- /// @param sigData the signature data; could be 1 or more packed signatures.
- /// @param offset the offset in sigData from which to start unpacking the signature components.
- function extractSignature(bytes memory sigData, uint256 offset) internal pure returns (bytes32 r, bytes32 s, uint8 v) {
- // Divide the signature in r, s and v variables
- // ecrecover takes the signature parameters, and the only way to get them
- // currently is to use assembly.
- // solium-disable-next-line security/no-inline-assembly
- assembly {
- let dataPointer := add(sigData, offset)
- r := mload(add(dataPointer, 0x20))
- s := mload(add(dataPointer, 0x40))
- v := byte(0, mload(add(dataPointer, 0x60)))
- }
-
- return (r, s, v);
- }
-}
-
-// File: contracts/Wallet/CoreWallet.sol
-
-pragma solidity ^0.5.10;
-
-
-
-
-
-
-
-/// @title Core Wallet
-/// @notice A basic smart contract wallet with cosigner functionality. The notion of "cosigner" is
-/// the simplest possible multisig solution, a two-of-two signature scheme. It devolves nicely
-/// to "one-of-one" (i.e. singlesig) by simply having the cosigner set to the same value as
-/// the main signer.
-///
-/// Most "advanced" functionality (deadman's switch, multiday recovery flows, blacklisting, etc)
-/// can be implemented externally to this smart contract, either as an additional smart contract
-/// (which can be tracked as a signer without cosigner, or as a cosigner) or as an off-chain flow
-/// using a public/private key pair as cosigner. Of course, the basic cosigning functionality could
-/// also be implemented in this way, but (A) the complexity and gas cost of two-of-two multisig (as
-/// implemented here) is negligable even if you don't need the cosigner functionality, and
-/// (B) two-of-two multisig (as implemented here) handles a lot of really common use cases, most
-/// notably third-party gas payment and off-chain blacklisting and fraud detection.
-contract CoreWallet is ERC721Receivable, ERC223Receiver, ERC1271, ERC1155TokenReceiver {
-
- using ECDSA for bytes;
-
- /// @notice We require that presigned transactions use the EIP-191 signing format.
- /// See that EIP for more info: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-191.md
- byte public constant EIP191_VERSION_DATA = byte(0);
- byte public constant EIP191_PREFIX = byte(0x19);
-
- /// @notice This is the version of the contract.
- string public constant VERSION = "1.1.0";
-
- /// @notice This is a sentinel value used to determine when a delegate is set to expose
- /// support for an interface containing more than a single function. See `delegates` and
- /// `setDelegate` for more information.
- address public constant COMPOSITE_PLACEHOLDER = address(1);
-
- /// @notice A pre-shifted "1", used to increment the authVersion, so we can "prepend"
- /// the authVersion to an address (for lookups in the authorizations mapping)
- /// by using the '+' operator (which is cheaper than a shift and a mask). See the
- /// comment on the `authorizations` variable for how this is used.
- uint256 public constant AUTH_VERSION_INCREMENTOR = (1 << 160);
-
- /// @notice The pre-shifted authVersion (to get the current authVersion as an integer,
- /// shift this value right by 160 bits). Starts as `1 << 160` (`AUTH_VERSION_INCREMENTOR`)
- /// See the comment on the `authorizations` variable for how this is used.
- uint256 public authVersion;
-
- /// @notice A mapping containing all of the addresses that are currently authorized to manage
- /// the assets owned by this wallet.
- ///
- /// The keys in this mapping are authorized addresses with a version number prepended,
- /// like so: (authVersion,96)(address,160). The current authVersion MUST BE included
- /// for each look-up; this allows us to effectively clear the entire mapping of its
- /// contents merely by incrementing the authVersion variable. (This is important for
- /// the emergencyRecovery() method.) Inspired by https://ethereum.stackexchange.com/a/42540
- ///
- /// The values in this mapping are 256bit words, whose lower 20 bytes constitute "cosigners"
- /// for each address. If an address maps to itself, then that address is said to have no cosigner.
- ///
- /// The upper 12 bytes are reserved for future meta-data purposes. The meta-data could refer
- /// to the key (authorized address) or the value (cosigner) of the mapping.
- ///
- /// Addresses that map to a non-zero cosigner in the current authVersion are called
- /// "authorized addresses".
- mapping(uint256 => uint256) public authorizations;
-
- /// @notice A per-key nonce value, incremented each time a transaction is processed with that key.
- /// Used for replay prevention. The nonce value in the transaction must exactly equal the current
- /// nonce value in the wallet for that key. (This mirrors the way Ethereum's transaction nonce works.)
- mapping(address => uint256) public nonces;
-
- /// @notice A mapping tracking dynamically supported interfaces and their corresponding
- /// implementation contracts. Keys are interface IDs and values are addresses of
- /// contracts that are responsible for implementing the function corresponding to the
- /// interface.
- ///
- /// Delegates are added (or removed) via the `setDelegate` method after the contract is
- /// deployed, allowing support for new interfaces to be dynamically added after deployment.
- /// When a delegate is added, its interface ID is considered "supported" under EIP165.
- ///
- /// For cases where an interface composed of more than a single function must be
- /// supported, it is necessary to manually add the composite interface ID with
- /// `setDelegate(interfaceId, COMPOSITE_PLACEHOLDER)`. Interface IDs added with the
- /// COMPOSITE_PLACEHOLDER address are ignored when called and are only used to specify
- /// supported interfaces.
- mapping(bytes4 => address) public delegates;
-
- /// @notice A special address that is authorized to call `emergencyRecovery()`. That function
- /// resets ALL authorization for this wallet, and must therefore be treated with utmost security.
- /// Reasonable choices for recoveryAddress include:
- /// - the address of a private key in cold storage
- /// - a physically secured hardware wallet
- /// - a multisig smart contract, possibly with a time-delayed challenge period
- /// - the zero address, if you like performing without a safety net ;-)
- address public recoveryAddress;
-
- /// @notice Used to track whether or not this contract instance has been initialized. This
- /// is necessary since it is common for this wallet smart contract to be used as the "library
- /// code" for an clone contract. See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1167.md
- /// for more information about clone contracts.
- bool public initialized;
-
- /// @notice Used to decorate methods that can only be called directly by the recovery address.
- modifier onlyRecoveryAddress() {
- require(msg.sender == recoveryAddress, "sender must be recovery address");
- _;
- }
-
- /// @notice Used to decorate the `init` function so this can only be called one time. Necessary
- /// since this contract will often be used as a "clone". (See above.)
- modifier onlyOnce() {
- require(!initialized, "must not already be initialized");
- initialized = true;
- _;
- }
-
- /// @notice Used to decorate methods that can only be called indirectly via an `invoke()` method.
- /// In practice, it means that those methods can only be called by a signer/cosigner
- /// pair that is currently authorized. Theoretically, we could factor out the
- /// signer/cosigner verification code and use it explicitly in this modifier, but that
- /// would either result in duplicated code, or additional overhead in the invoke()
- /// calls (due to the stack manipulation for calling into the shared verification function).
- /// Doing it this way makes calling the administration functions more expensive (since they
- /// go through a explicit call() instead of just branching within the contract), but it
- /// makes invoke() more efficient. We assume that invoke() will be used much, much more often
- /// than any of the administration functions.
- modifier onlyInvoked() {
- require(msg.sender == address(this), "must be called from `invoke()`");
- _;
- }
-
- /// @notice Emitted when an authorized address is added, removed, or modified. When an
- /// authorized address is removed ("deauthorized"), cosigner will be address(0) in
- /// this event.
- ///
- /// NOTE: When emergencyRecovery() is called, all existing addresses are deauthorized
- /// WITHOUT Authorized(addr, 0) being emitted. If you are keeping an off-chain mirror of
- /// authorized addresses, you must also watch for EmergencyRecovery events.
- /// @dev hash is 0xf5a7f4fb8a92356e8c8c4ae7ac3589908381450500a7e2fd08c95600021ee889
- /// @param authorizedAddress the address to authorize or unauthorize
- /// @param cosigner the 2-of-2 signatory (optional).
- event Authorized(address authorizedAddress, uint256 cosigner);
-
- /// @notice Emitted when an emergency recovery has been performed. If this event is fired,
- /// ALL previously authorized addresses have been deauthorized and the only authorized
- /// address is the authorizedAddress indicated in this event.
- /// @dev hash is 0xe12d0bbeb1d06d7a728031056557140afac35616f594ef4be227b5b172a604b5
- /// @param authorizedAddress the new authorized address
- /// @param cosigner the cosigning address for `authorizedAddress`
- event EmergencyRecovery(address authorizedAddress, uint256 cosigner);
-
- /// @notice Emitted when the recovery address changes. Either (but not both) of the
- /// parameters may be zero.
- /// @dev hash is 0x568ab3dedd6121f0385e007e641e74e1f49d0fa69cab2957b0b07c4c7de5abb6
- /// @param previousRecoveryAddress the previous recovery address
- /// @param newRecoveryAddress the new recovery address
- event RecoveryAddressChanged(address previousRecoveryAddress, address newRecoveryAddress);
-
- /// @dev Emitted when this contract receives a non-zero amount ether via the fallback function
- /// (i.e. This event is not fired if the contract receives ether as part of a method invocation)
- /// @param from the address which sent you ether
- /// @param value the amount of ether sent
- event Received(address from, uint value);
-
- /// @notice Emitted whenever a transaction is processed successfully from this wallet. Includes
- /// both simple send ether transactions, as well as other smart contract invocations.
- /// @dev hash is 0x101214446435ebbb29893f3348e3aae5ea070b63037a3df346d09d3396a34aee
- /// @param hash The hash of the entire operation set. 0 is returned when emitted from `invoke0()`.
- /// @param result A bitfield of the results of the operations. A bit of 0 means success, and 1 means failure.
- /// @param numOperations A count of the number of operations processed
- event InvocationSuccess(
- bytes32 hash,
- uint256 result,
- uint256 numOperations
- );
-
- /// @notice Emitted when a delegate is added or removed.
- /// @param interfaceId The interface ID as specified by EIP165
- /// @param delegate The address of the contract implementing the given function. If this is
- /// COMPOSITE_PLACEHOLDER, we are indicating support for a composite interface.
- event DelegateUpdated(bytes4 interfaceId, address delegate);
-
- /// @notice The shared initialization code used to setup the contract state regardless of whether or
- /// not the clone pattern is being used.
- /// @param _authorizedAddress the initial authorized address, must not be zero!
- /// @param _cosigner the initial cosigning address for `_authorizedAddress`, can be equal to `_authorizedAddress`
- /// @param _recoveryAddress the initial recovery address for the wallet, can be address(0)
- function init(address _authorizedAddress, uint256 _cosigner, address _recoveryAddress) public onlyOnce {
- require(_authorizedAddress != _recoveryAddress, "Do not use the recovery address as an authorized address.");
- require(address(_cosigner) != _recoveryAddress, "Do not use the recovery address as a cosigner.");
- require(_authorizedAddress != address(0), "Authorized addresses must not be zero.");
- require(address(_cosigner) != address(0), "Initial cosigner must not be zero.");
-
- recoveryAddress = _recoveryAddress;
- // set initial authorization value
- authVersion = AUTH_VERSION_INCREMENTOR;
- // add initial authorized address
- authorizations[authVersion + uint256(_authorizedAddress)] = _cosigner;
-
- emit Authorized(_authorizedAddress, _cosigner);
- }
-
- function bytesToAddresses(bytes memory bys) private pure returns (address[] memory addresses) {
- addresses = new address[](bys.length/20);
- for (uint i=0; i < bys.length; i+=20) {
- address addr;
- uint end = i+20;
- assembly {
- addr := mload(add(bys,end))
- }
- addresses[i/20] = addr;
- }
- }
-
- function init2(bytes memory _authorizedAddresses, uint256 _cosigner, address _recoveryAddress) public onlyOnce {
- address[] memory addresses = bytesToAddresses(_authorizedAddresses);
- for (uint i=0; i < addresses.length; i++) {
- address _authorizedAddress = addresses[i];
- require(_authorizedAddress != _recoveryAddress, "Do not use the recovery address as an authorized address.");
- require(address(_cosigner) != _recoveryAddress, "Do not use the recovery address as a cosigner.");
- require(_authorizedAddress != address(0), "Authorized addresses must not be zero.");
- require(address(_cosigner) != address(0), "Initial cosigner must not be zero.");
-
- recoveryAddress = _recoveryAddress;
- // set initial authorization value
- authVersion = AUTH_VERSION_INCREMENTOR;
- // add initial authorized address
- authorizations[authVersion + uint256(_authorizedAddress)] = _cosigner;
-
- emit Authorized(_authorizedAddress, _cosigner);
- }
- }
-
- /// @notice The fallback function, invoked whenever we receive a transaction that doesn't call any of our
- /// named functions. In particular, this method is called when we are the target of a simple send
- /// transaction, when someone calls a method we have dynamically added a delegate for, or when someone
- /// tries to call a function we don't implement, either statically or dynamically.
- ///
- /// A correct invocation of this method occurs in two cases:
- /// - someone transfers ETH to this wallet (`msg.data.length` is 0)
- /// - someone calls a delegated function (`msg.data.length` is greater than 0 and
- /// `delegates[msg.sig]` is set)
- /// In all other cases, this function will revert.
- ///
- /// NOTE: Some smart contracts send 0 eth as part of a more complex operation
- /// (-cough- CryptoKitties -cough-); ideally, we'd `require(msg.value > 0)` here when
- /// `msg.data.length == 0`, but to work with those kinds of smart contracts, we accept zero sends
- /// and just skip logging in that case.
- function() external payable {
- if (msg.value > 0) {
- emit Received(msg.sender, msg.value);
- }
- if (msg.data.length > 0) {
- address delegate = delegates[msg.sig];
- require(delegate > COMPOSITE_PLACEHOLDER, "Invalid transaction");
-
- // We have found a delegate contract that is responsible for the method signature of
- // this call. Now, pass along the calldata of this CALL to the delegate contract.
- assembly {
- calldatacopy(0, 0, calldatasize())
- let result := staticcall(gas, delegate, 0, calldatasize(), 0, 0)
- returndatacopy(0, 0, returndatasize())
-
- // If the delegate reverts, we revert. If the delegate does not revert, we return the data
- // returned by the delegate to the original caller.
- switch result
- case 0 {
- revert(0, returndatasize())
- }
- default {
- return(0, returndatasize())
- }
- }
- }
- }
-
- /// @notice Adds or removes dynamic support for an interface. Can be used in 3 ways:
- /// - Add a contract "delegate" that implements a single function
- /// - Remove delegate for a function
- /// - Specify that an interface ID is "supported", without adding a delegate. This is
- /// used for composite interfaces when the interface ID is not a single method ID.
- /// @dev Must be called through `invoke`
- /// @param _interfaceId The ID of the interface we are adding support for
- /// @param _delegate Either:
- /// - the address of a contract that implements the function specified by `_interfaceId`
- /// for adding an implementation for a single function
- /// - 0 for removing an existing delegate
- /// - COMPOSITE_PLACEHOLDER for specifying support for a composite interface
- function setDelegate(bytes4 _interfaceId, address _delegate) external onlyInvoked {
- delegates[_interfaceId] = _delegate;
- emit DelegateUpdated(_interfaceId, _delegate);
- }
-
- /// @notice Configures an authorizable address. Can be used in four ways:
- /// - Add a new signer/cosigner pair (cosigner must be non-zero)
- /// - Set or change the cosigner for an existing signer (if authorizedAddress != cosigner)
- /// - Remove the cosigning requirement for a signer (if authorizedAddress == cosigner)
- /// - Remove a signer (if cosigner == address(0))
- /// @dev Must be called through `invoke()`
- /// @param _authorizedAddress the address to configure authorization
- /// @param _cosigner the corresponding cosigning address
- function setAuthorized(address _authorizedAddress, uint256 _cosigner) external onlyInvoked {
- // TODO: Allowing a signer to remove itself is actually pretty terrible; it could result in the user
- // removing their only available authorized key. Unfortunately, due to how the invocation forwarding
- // works, we don't actually _know_ which signer was used to call this method, so there's no easy way
- // to prevent this.
-
- // TODO: Allowing the backup key to be set as an authorized address bypasses the recovery mechanisms.
- // Dapper can prevent this with offchain logic and the cosigner, but it would be nice to have
- // this enforced by the smart contract logic itself.
-
- require(_authorizedAddress != address(0), "Authorized addresses must not be zero.");
- require(_authorizedAddress != recoveryAddress, "Do not use the recovery address as an authorized address.");
- require(address(_cosigner) == address(0) || address(_cosigner) != recoveryAddress, "Do not use the recovery address as a cosigner.");
-
- authorizations[authVersion + uint256(_authorizedAddress)] = _cosigner;
- emit Authorized(_authorizedAddress, _cosigner);
- }
-
- /// @notice Performs an emergency recovery operation, removing all existing authorizations and setting
- /// a sole new authorized address with optional cosigner. THIS IS A SCORCHED EARTH SOLUTION, and great
- /// care should be taken to ensure that this method is never called unless it is a last resort. See the
- /// comments above about the proper kinds of addresses to use as the recoveryAddress to ensure this method
- /// is not trivially abused.
- /// @param _authorizedAddress the new and sole authorized address
- /// @param _cosigner the corresponding cosigner address, can be equal to _authorizedAddress
- function emergencyRecovery(address _authorizedAddress, uint256 _cosigner) external onlyRecoveryAddress {
- require(_authorizedAddress != address(0), "Authorized addresses must not be zero.");
- require(_authorizedAddress != recoveryAddress, "Do not use the recovery address as an authorized address.");
- require(address(_cosigner) != address(0), "The cosigner must not be zero.");
-
- // Incrementing the authVersion number effectively erases the authorizations mapping. See the comments
- // on the authorizations variable (above) for more information.
- authVersion += AUTH_VERSION_INCREMENTOR;
-
- // Store the new signer/cosigner pair as the only remaining authorized address
- authorizations[authVersion + uint256(_authorizedAddress)] = _cosigner;
- emit EmergencyRecovery(_authorizedAddress, _cosigner);
- }
-
- function emergencyRecovery2(address _authorizedAddress, uint256 _cosigner, address _recoveryAddress) external onlyRecoveryAddress {
- require(_authorizedAddress != address(0), "Authorized addresses must not be zero.");
- require(_authorizedAddress != _recoveryAddress, "Do not use the recovery address as an authorized address.");
- require(address(_cosigner) != address(0), "The cosigner must not be zero.");
-
- // Incrementing the authVersion number effectively erases the authorizations mapping. See the comments
- // on the authorizations variable (above) for more information.
- authVersion += AUTH_VERSION_INCREMENTOR;
-
- // Store the new signer/cosigner pair as the only remaining authorized address
- authorizations[authVersion + uint256(_authorizedAddress)] = _cosigner;
-
- // set new recovery address
- address previous = recoveryAddress;
- recoveryAddress = _recoveryAddress;
-
- emit RecoveryAddressChanged(previous, recoveryAddress);
- emit EmergencyRecovery(_authorizedAddress, _cosigner);
- }
-
- /// @notice Sets the recovery address, which can be zero (indicating that no recovery is possible)
- /// Can be updated by any authorized address. This address should be set with GREAT CARE. See the
- /// comments above about the proper kinds of addresses to use as the recoveryAddress to ensure this
- /// mechanism is not trivially abused.
- /// @dev Must be called through `invoke()`
- /// @param _recoveryAddress the new recovery address
- function setRecoveryAddress(address _recoveryAddress) external onlyInvoked {
- require(
- address(authorizations[authVersion + uint256(_recoveryAddress)]) == address(0),
- "Do not use an authorized address as the recovery address."
- );
-
- address previous = recoveryAddress;
- recoveryAddress = _recoveryAddress;
-
- emit RecoveryAddressChanged(previous, recoveryAddress);
- }
-
- /// @notice Allows ANY caller to recover gas by way of deleting old authorization keys after
- /// a recovery operation. Anyone can call this method to delete the old unused storage and
- /// get themselves a bit of gas refund in the bargin.
- /// @dev keys must be known to caller or else nothing is refunded
- /// @param _version the version of the mapping which you want to delete (unshifted)
- /// @param _keys the authorization keys to delete
- function recoverGas(uint256 _version, address[] calldata _keys) external {
- // TODO: should this be 0xffffffffffffffffffffffff ?
- require(_version > 0 && _version < 0xffffffff, "Invalid version number.");
-
- uint256 shiftedVersion = _version << 160;
-
- require(shiftedVersion < authVersion, "You can only recover gas from expired authVersions.");
-
- for (uint256 i = 0; i < _keys.length; ++i) {
- delete(authorizations[shiftedVersion + uint256(_keys[i])]);
- }
- }
-
- /// @notice Should return whether the signature provided is valid for the provided data
- /// See https://github.com/ethereum/EIPs/issues/1271
- /// @dev This function meets the following conditions as per the EIP:
- /// MUST return the bytes4 magic value `0x1626ba7e` when function passes.
- /// MUST NOT modify state (using `STATICCALL` for solc < 0.5, `view` modifier for solc > 0.5)
- /// MUST allow external calls
- /// @param hash A 32 byte hash of the signed data. The actual hash that is hashed however is the
- /// the following tightly packed arguments: `0x19,0x0,wallet_address,hash`
- /// @param _signature Signature byte array associated with `_data`
- /// @return Magic value `0x1626ba7e` upon success, 0 otherwise.
- function isValidSignature(bytes32 hash, bytes calldata _signature) external view returns (bytes4) {
-
- // We 'hash the hash' for the following reasons:
- // 1. `hash` is not the hash of an Ethereum transaction
- // 2. signature must target this wallet to avoid replaying the signature for another wallet
- // with the same key
- // 3. Gnosis does something similar:
- // https://github.com/gnosis/safe-contracts/blob/102e632d051650b7c4b0a822123f449beaf95aed/contracts/GnosisSafe.sol
- bytes32 operationHash = keccak256(
- abi.encodePacked(
- EIP191_PREFIX,
- EIP191_VERSION_DATA,
- this,
- hash));
-
- bytes32[2] memory r;
- bytes32[2] memory s;
- uint8[2] memory v;
- address signer;
- address cosigner;
-
- // extract 1 or 2 signatures depending on length
- if (_signature.length == 65) {
- (r[0], s[0], v[0]) = _signature.extractSignature(0);
- signer = ecrecover(operationHash, v[0], r[0], s[0]);
- cosigner = signer;
- } else if (_signature.length == 130) {
- (r[0], s[0], v[0]) = _signature.extractSignature(0);
- (r[1], s[1], v[1]) = _signature.extractSignature(65);
- signer = ecrecover(operationHash, v[0], r[0], s[0]);
- cosigner = ecrecover(operationHash, v[1], r[1], s[1]);
- } else {
- return 0;
- }
-
- // check for valid signature
- if (signer == address(0)) {
- return 0;
- }
-
- // check for valid signature
- if (cosigner == address(0)) {
- return 0;
- }
-
- // check to see if this is an authorized key
- if (address(authorizations[authVersion + uint256(signer)]) != cosigner) {
- return 0;
- }
-
- return ERC1271_VALIDSIGNATURE;
- }
-
- /// @notice Query if this contract implements an interface. This function takes into account
- /// interfaces we implement dynamically through delegates. For interfaces that are just a
- /// single method, using `setDelegate` will result in that method's ID returning true from
- /// `supportsInterface`. For composite interfaces that are composed of multiple functions, it is
- /// necessary to add the interface ID manually with `setDelegate(interfaceID,
- /// COMPOSITE_PLACEHOLDER)`
- /// IN ADDITION to adding each function of the interface as usual.
- /// @param interfaceID The interface identifier, as specified in ERC-165
- /// @dev Interface identification is specified in ERC-165. This function
- /// uses less than 30,000 gas.
- /// @return `true` if the contract implements `interfaceID` and
- /// `interfaceID` is not 0xffffffff, `false` otherwise
- function supportsInterface(bytes4 interfaceID) external view returns (bool) {
- // First check if the ID matches one of the interfaces we support statically.
- if (
- interfaceID == this.supportsInterface.selector || // ERC165
- interfaceID == ERC721_RECEIVED_FINAL || // ERC721 Final
- interfaceID == ERC721_RECEIVED_DRAFT || // ERC721 Draft
- interfaceID == ERC223_ID || // ERC223
- interfaceID == ERC1155_TOKEN_RECIEVER || // ERC1155 Token Reciever
- interfaceID == ERC1271_VALIDSIGNATURE // ERC1271
- ) {
- return true;
- }
- // If we don't support the interface statically, check whether we have added
- // dynamic support for it.
- return uint256(delegates[interfaceID]) > 0;
- }
-
- /// @notice A version of `invoke()` that has no explicit signatures, and uses msg.sender
- /// as both the signer and cosigner. Will only succeed if `msg.sender` is an authorized
- /// signer for this wallet, with no cosigner, saving transaction size and gas in that case.
- /// @param data The data containing the transactions to be invoked; see internalInvoke for details.
- function invoke0(bytes calldata data) external {
- // The nonce doesn't need to be incremented for transactions that don't include explicit signatures;
- // the built-in nonce of the native ethereum transaction will protect against replay attacks, and we
- // can save the gas that would be spent updating the nonce variable
-
- // The operation should be approved if the signer address has no cosigner (i.e. signer == cosigner)
- require(address(authorizations[authVersion + uint256(msg.sender)]) == msg.sender, "Invalid authorization.");
-
- internalInvoke(0, data);
- }
-
- /// @notice A version of `invoke()` that has one explicit signature which is used to derive the authorized
- /// address. Uses `msg.sender` as the cosigner.
- /// @param v the v value for the signature; see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
- /// @param r the r value for the signature
- /// @param s the s value for the signature
- /// @param nonce the nonce value for the signature
- /// @param authorizedAddress the address of the authorization key; this is used here so that cosigner signatures are interchangeable
- /// between this function and `invoke2()`
- /// @param data The data containing the transactions to be invoked; see internalInvoke for details.
- function invoke1CosignerSends(uint8 v, bytes32 r, bytes32 s, uint256 nonce, address authorizedAddress, bytes calldata data) external {
- // check signature version
- require(v == 27 || v == 28, "Invalid signature version.");
-
- // calculate hash
- bytes32 operationHash = keccak256(
- abi.encodePacked(
- EIP191_PREFIX,
- EIP191_VERSION_DATA,
- this,
- nonce,
- authorizedAddress,
- data));
-
- // recover signer
- address signer = ecrecover(operationHash, v, r, s);
-
- // check for valid signature
- require(signer != address(0), "Invalid signature.");
-
- // check nonce
- require(nonce > nonces[signer], "must use valid nonce for signer");
-
- // check signer
- require(signer == authorizedAddress, "authorized addresses must be equal");
-
- // Get cosigner
- address requiredCosigner = address(authorizations[authVersion + uint256(signer)]);
-
- // The operation should be approved if the signer address has no cosigner (i.e. signer == cosigner) or
- // if the actual cosigner matches the required cosigner.
- require(requiredCosigner == signer || requiredCosigner == msg.sender, "Invalid authorization.");
-
- // increment nonce to prevent replay attacks
- nonces[signer] = nonce;
-
- // call internal function
- internalInvoke(operationHash, data);
- }
-
- /// @notice A version of `invoke()` that has one explicit signature which is used to derive the cosigning
- /// address. Uses `msg.sender` as the authorized address.
- /// @param v the v value for the signature; see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md
- /// @param r the r value for the signature
- /// @param s the s value for the signature
- /// @param data The data containing the transactions to be invoked; see internalInvoke for details.
- function invoke1SignerSends(uint8 v, bytes32 r, bytes32 s, bytes calldata data) external {
- // check signature version
- // `ecrecover` will in fact return 0 if given invalid
- // so perhaps this check is redundant
- require(v == 27 || v == 28, "Invalid signature version.");
-
- uint256 nonce = nonces[msg.sender];
-
- // calculate hash
- bytes32 operationHash = keccak256(
- abi.encodePacked(
- EIP191_PREFIX,
- EIP191_VERSION_DATA,
- this,
- nonce,
- msg.sender,
- data));
-
- // recover cosigner
- address cosigner = ecrecover(operationHash, v, r, s);
-
- // check for valid signature
- require(cosigner != address(0), "Invalid signature.");
-
- // Get required cosigner
- address requiredCosigner = address(authorizations[authVersion + uint256(msg.sender)]);
-
- // The operation should be approved if the signer address has no cosigner (i.e. signer == cosigner) or
- // if the actual cosigner matches the required cosigner.
- require(requiredCosigner == cosigner || requiredCosigner == msg.sender, "Invalid authorization.");
-
- // increment nonce to prevent replay attacks
- nonces[msg.sender] = nonce + 1;
-
- internalInvoke(operationHash, data);
- }
-
- /// @notice A version of `invoke()` that has two explicit signatures, the first is used to derive the authorized
- /// address, the second to derive the cosigner. The value of `msg.sender` is ignored.
- /// @param v the v values for the signatures
- /// @param r the r values for the signatures
- /// @param s the s values for the signatures
- /// @param nonce the nonce value for the signature
- /// @param authorizedAddress the address of the signer; forces the signature to be unique and tied to the signers nonce
- /// @param data The data containing the transactions to be invoked; see internalInvoke for details.
- function invoke2(uint8[2] calldata v, bytes32[2] calldata r, bytes32[2] calldata s, uint256 nonce, address authorizedAddress, bytes calldata data) external {
- // check signature versions
- // `ecrecover` will infact return 0 if given invalid
- // so perhaps these checks are redundant
- require(v[0] == 27 || v[0] == 28, "invalid signature version v[0]");
- require(v[1] == 27 || v[1] == 28, "invalid signature version v[1]");
-
- bytes32 operationHash = keccak256(
- abi.encodePacked(
- EIP191_PREFIX,
- EIP191_VERSION_DATA,
- this,
- nonce,
- authorizedAddress,
- data));
-
- // recover signer and cosigner
- address signer = ecrecover(operationHash, v[0], r[0], s[0]);
- address cosigner = ecrecover(operationHash, v[1], r[1], s[1]);
-
- // check for valid signatures
- require(signer != address(0), "Invalid signature for signer.");
- require(cosigner != address(0), "Invalid signature for cosigner.");
-
- // check signer address
- require(signer == authorizedAddress, "authorized addresses must be equal");
-
- // check nonces
- require(nonce > nonces[signer], "must use valid nonce for signer");
-
- // Get Mapping
- address requiredCosigner = address(authorizations[authVersion + uint256(signer)]);
-
- // The operation should be approved if the signer address has no cosigner (i.e. signer == cosigner) or
- // if the actual cosigner matches the required cosigner.
- require(requiredCosigner == signer || requiredCosigner == cosigner, "Invalid authorization.");
-
- // increment nonce to prevent replay attacks
- nonces[signer] = nonce;
-
- internalInvoke(operationHash, data);
- }
-
- /// @dev Internal invoke call,
- /// @param operationHash The hash of the operation
- /// @param data The data to send to the `call()` operation
- /// The data is prefixed with a global 1 byte revert flag
- /// If revert is 1, then any revert from a `call()` operation is rethrown.
- /// Otherwise, the error is recorded in the `result` field of the `InvocationSuccess` event.
- /// Immediately following the revert byte (no padding), the data format is then is a series
- /// of 1 or more tightly packed tuples:
- /// ``
- /// If `datalength == 0`, the data field must be omitted
- function internalInvoke(bytes32 operationHash, bytes memory data) internal {
- // keep track of the number of operations processed
- uint256 numOps;
- // keep track of the result of each operation as a bit
- uint256 result;
-
- // We need to store a reference to this string as a variable so we can use it as an argument to
- // the revert call from assembly.
- string memory invalidLengthMessage = "Data field too short";
- string memory callFailed = "Call failed";
-
- // At an absolute minimum, the data field must be at least 85 bytes
- //
- require(data.length >= 85, invalidLengthMessage);
-
- // Forward the call onto its actual target. Note that the target address can be `self` here, which is
- // actually the required flow for modifying the configuration of the authorized keys and recovery address.
- //
- // The assembly code below loads data directly from memory, so the enclosing function must be marked `internal`
- assembly {
- // A cursor pointing to the revert flag, starts after the length field of the data object
- let memPtr := add(data, 32)
-
- // The revert flag is the leftmost byte from memPtr
- let revertFlag := byte(0, mload(memPtr))
-
- // A pointer to the end of the data object
- let endPtr := add(memPtr, mload(data))
-
- // Now, memPtr is a cursor pointing to the beginning of the current sub-operation
- memPtr := add(memPtr, 1)
-
- // Loop through data, parsing out the various sub-operations
- for { } lt(memPtr, endPtr) { } {
- // Load the length of the call data of the current operation
- // 52 = to(20) + value(32)
- let len := mload(add(memPtr, 52))
-
- // Compute a pointer to the end of the current operation
- // 84 = to(20) + value(32) + size(32)
- let opEnd := add(len, add(memPtr, 84))
-
- // Bail if the current operation's data overruns the end of the enclosing data buffer
- // NOTE: Comment out this bit of code and uncomment the next section if you want
- // the solidity-coverage tool to work.
- // See https://github.com/sc-forks/solidity-coverage/issues/287
- if gt(opEnd, endPtr) {
- // The computed end of this operation goes past the end of the data buffer. Not good!
- revert(add(invalidLengthMessage, 32), mload(invalidLengthMessage))
- }
- // NOTE: Code that is compatible with solidity-coverage
- // switch gt(opEnd, endPtr)
- // case 1 {
- // revert(add(invalidLengthMessage, 32), mload(invalidLengthMessage))
- // }
-
- // This line of code packs in a lot of functionality!
- // - load the target address from memPtr, the address is only 20-bytes but mload always grabs 32-bytes,
- // so we have to shr by 12 bytes.
- // - load the value field, stored at memPtr+20
- // - pass a pointer to the call data, stored at memPtr+84
- // - use the previously loaded len field as the size of the call data
- // - make the call (passing all remaining gas to the child call)
- // - check the result (0 == reverted)
- if eq(0, call(gas, shr(96, mload(memPtr)), mload(add(memPtr, 20)), add(memPtr, 84), len, 0, 0)) {
- switch revertFlag
- case 1 {
- revert(add(callFailed, 32), mload(callFailed))
- }
- default {
- // mark this operation as failed
- // create the appropriate bit, 'or' with previous
- result := or(result, exp(2, numOps))
- }
- }
-
- // increment our counter
- numOps := add(numOps, 1)
-
- // Update mem pointer to point to the next sub-operation
- memPtr := opEnd
- }
- }
-
- // emit single event upon success
- emit InvocationSuccess(operationHash, result, numOps);
- }
-}
-
-// File: contracts/Wallet/CloneableWallet.sol
-
-pragma solidity ^0.5.10;
-
-
-
-/// @title Cloneable Wallet
-/// @notice This contract represents a complete but non working wallet.
-/// It is meant to be deployed and serve as the contract that you clone
-/// in an EIP 1167 clone setup.
-/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1167.md
-/// @dev Currently, we are seeing approximatley 933 gas overhead for using
-/// the clone wallet; use `FullWallet` if you think users will overtake
-/// the transaction threshold over the lifetime of the wallet.
-contract CloneableWallet is CoreWallet {
-
- /// @dev An empty constructor that deploys a NON-FUNCTIONAL version
- /// of `CoreWallet`
- constructor () public {
- initialized = true;
- }
-}
-
-// File: contracts/Ownership/Ownable.sol
-
-pragma solidity ^0.5.10;
-
-
-/// @title Ownable is for contracts that can be owned.
-/// @dev The Ownable contract keeps track of an owner address,
-/// and provides basic authorization functions.
-contract Ownable {
-
- /// @dev the owner of the contract
- address public owner;
-
- /// @dev Fired when the owner to renounce ownership, leaving no one
- /// as the owner.
- /// @param previousOwner The previous `owner` of this contract
- event OwnershipRenounced(address indexed previousOwner);
-
- /// @dev Fired when the owner to changes ownership
- /// @param previousOwner The previous `owner`
- /// @param newOwner The new `owner`
- event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-
- /// @dev sets the `owner` to `msg.sender`
- constructor() public {
- owner = msg.sender;
- }
-
- /// @dev Throws if the `msg.sender` is not the current `owner`
- modifier onlyOwner() {
- require(msg.sender == owner, "must be owner");
- _;
- }
-
- /// @dev Allows the current `owner` to renounce ownership
- function renounceOwnership() external onlyOwner {
- emit OwnershipRenounced(owner);
- owner = address(0);
- }
-
- /// @dev Allows the current `owner` to transfer ownership
- /// @param _newOwner The new `owner`
- function transferOwnership(address _newOwner) external onlyOwner {
- _transferOwnership(_newOwner);
- }
-
- /// @dev Internal version of `transferOwnership`
- /// @param _newOwner The new `owner`
- function _transferOwnership(address _newOwner) internal {
- require(_newOwner != address(0), "cannot renounce ownership");
- emit OwnershipTransferred(owner, _newOwner);
- owner = _newOwner;
- }
-}
-
-// File: contracts/Ownership/HasNoEther.sol
-
-pragma solidity ^0.5.10;
-
-
-
-/// @title HasNoEther is for contracts that should not own Ether
-contract HasNoEther is Ownable {
-
- /// @dev This contructor rejects incoming Ether
- constructor() public payable {
- require(msg.value == 0, "must not send Ether");
- }
-
- /// @dev Disallows direct send by default function not being `payable`
- function() external {}
-
- /// @dev Transfers all Ether held by this contract to the owner.
- function reclaimEther() external onlyOwner {
- msg.sender.transfer(address(this).balance);
- }
-}
-
-// File: contracts/WalletFactory/CloneFactory.sol
-
-pragma solidity ^0.5.10;
-
-
-/// @title CloneFactory - a contract that creates clones
-/// @dev See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1167.md
-/// @dev See https://github.com/optionality/clone-factory/blob/master/contracts/CloneFactory.sol
-contract CloneFactory {
- event CloneCreated(address indexed target, address clone);
-
- function createClone(address target) internal returns (address payable result) {
- bytes20 targetBytes = bytes20(target);
- assembly {
- let clone := mload(0x40)
- mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
- mstore(add(clone, 0x14), targetBytes)
- mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
- result := create(0, clone, 0x37)
- }
- }
-
- function createClone2(address target, bytes32 salt) internal returns (address payable result) {
- bytes20 targetBytes = bytes20(target);
- assembly {
- let clone := mload(0x40)
- mstore(clone, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
- mstore(add(clone, 0x14), targetBytes)
- mstore(add(clone, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
- result := create2(0, clone, 0x37, salt)
- }
- }
-}
-
-// File: contracts/WalletFactory/FullWalletByteCode.sol
-
-pragma solidity ^0.5.10;
-
-/// @title FullWalletByteCode
-/// @dev A contract containing the FullWallet bytecode, for use in deployment.
-contract FullWalletByteCode {
- /// @notice This is the raw bytecode of the full wallet. It is encoded here as a raw byte
- /// array to support deployment with CREATE2, as Solidity's 'new' constructor system does
- /// not support CREATE2 yet.
- ///
- /// NOTE: Be sure to update this whenever the wallet bytecode changes!
- /// Simply run `npm run build` and then copy the `"bytecode"`
- /// portion from the `build/contracts/FullWallet.json` file to here,
- /// then append 64x3 0's.
- bytes constant fullWalletBytecode = hex'60806040523480156200001157600080fd5b50604051620033a7380380620033a7833981810160405260608110156200003757600080fd5b50805160208201516040909201519091906200005e8383836001600160e01b036200006716565b5050506200033b565b60045474010000000000000000000000000000000000000000900460ff1615620000f257604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f6d757374206e6f7420616c726561647920626520696e697469616c697a656400604482015290519081900360640190fd5b6004805460ff60a01b1916740100000000000000000000000000000000000000001790556001600160a01b0383811690821614156200017d576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526039815260200180620033406039913960400191505060405180910390fd5b806001600160a01b0316826001600160a01b03161415620001ea576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252602e81526020018062003379602e913960400191505060405180910390fd5b6001600160a01b0383166200024b576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526026815260200180620032f86026913960400191505060405180910390fd5b6001600160a01b038216620002ac576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806200331e6022913960400191505060405180910390fd5b600480546001600160a01b0319166001600160a01b03838116919091179091557401000000000000000000000000000000000000000060008181559185169081018252600160209081526040928390208590558251918252810184905281517fb39b5f240c7440b58c1c6cfd328b09ff9aa18b3c8ef4b829774e4f5bad039416929181900390910190a1505050565b612fad806200034b6000396000f3fe6080604052600436106101d85760003560e01c80637ecebe0011610102578063bc197c8111610095578063ef009e4211610064578063ef009e4214610c68578063f0b9e5ba14610cea578063f23a6e6114610d7a578063ffa1ad7414610e1a576101d8565b8063bc197c8114610a20578063bf4fb0c014610b54578063c0ee0b8a14610b8d578063ce2d4f9614610c53576101d8565b80639105d9c4116100d15780639105d9c4146108b657806391aeeedc146108cb578063a0a2daf014610971578063a3c89c4f146109a5576101d8565b80637ecebe00146107e857806388fb06e71461081b5780638bf788741461085e5780638fd45d1a14610873576101d8565b8063210d66f81161017a57806357e61e291161014957806357e61e29146106d8578063710eb26c14610769578063727b7acf1461079a57806375857eba146107d3576101d8565b8063210d66f8146105865780632698c20c146105c257806343fc00b81461066257806349efe5ae146106a5576101d8565b8063157ca6e4116101b6578063157ca6e4146103fe578063158ef93e146104bd5780631626ba7e146104d25780631cd61bad14610554576101d8565b806301ffc9a7146102b357806308405166146102fb578063150b7a021461032d575b3415610219576040805133815234602082015281517f88a5966d370b9919b20f3e2c13ff65706f196a4e32cc2c12bf57088f88525874929181900390910190a15b36156102b157600080356001600160e01b0319168152600360205260409020546001600160a01b03166001811161028d576040805162461bcd60e51b815260206004820152601360248201527224b73b30b634b2103a3930b739b0b1ba34b7b760691b604482015290519081900360640190fd5b3660008037600080366000845afa3d6000803e8080156102ac573d6000f35b3d6000fd5b005b3480156102bf57600080fd5b506102e7600480360360208110156102d657600080fd5b50356001600160e01b031916610ea4565b604080519115158252519081900360200190f35b34801561030757600080fd5b50610310610f7a565b604080516001600160e01b03199092168252519081900360200190f35b34801561033957600080fd5b506103106004803603608081101561035057600080fd5b6001600160a01b03823581169260208101359091169160408201359190810190608081016060820135600160201b81111561038a57600080fd5b82018360208201111561039c57600080fd5b803590602001918460018302840111600160201b831117156103bd57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610f85945050505050565b34801561040a57600080fd5b506102b16004803603606081101561042157600080fd5b810190602081018135600160201b81111561043b57600080fd5b82018360208201111561044d57600080fd5b803590602001918460018302840111600160201b8311171561046e57600080fd5b91908080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525092955050823593505050602001356001600160a01b0316610f95565b3480156104c957600080fd5b506102e76111ed565b3480156104de57600080fd5b50610310600480360360408110156104f557600080fd5b81359190810190604081016020820135600160201b81111561051657600080fd5b82018360208201111561052857600080fd5b803590602001918460018302840111600160201b8311171561054957600080fd5b5090925090506111fd565b34801561056057600080fd5b5061056961156a565b604080516001600160f81b03199092168252519081900360200190f35b34801561059257600080fd5b506105b0600480360360208110156105a957600080fd5b503561156f565b60408051918252519081900360200190f35b3480156105ce57600080fd5b506102b160048036036101208110156105e657600080fd5b6040820190608083019060c0840135906001600160a01b0360e086013516908501856101208101610100820135600160201b81111561062457600080fd5b82018360208201111561063657600080fd5b803590602001918460018302840111600160201b8311171561065757600080fd5b509092509050611581565b34801561066e57600080fd5b506102b16004803603606081101561068557600080fd5b506001600160a01b03813581169160208101359160409091013516611a30565b3480156106b157600080fd5b506102b1600480360360208110156106c857600080fd5b50356001600160a01b0316611c46565b3480156106e457600080fd5b506102b1600480360360808110156106fb57600080fd5b60ff8235169160208101359160408201359190810190608081016060820135600160201b81111561072b57600080fd5b82018360208201111561073d57600080fd5b803590602001918460018302840111600160201b8311171561075e57600080fd5b509092509050611d58565b34801561077557600080fd5b5061077e611fd5565b604080516001600160a01b039092168252519081900360200190f35b3480156107a657600080fd5b506102b1600480360360408110156107bd57600080fd5b506001600160a01b038135169060200135611fe4565b3480156107df57600080fd5b506105b0612199565b3480156107f457600080fd5b506105b06004803603602081101561080b57600080fd5b50356001600160a01b03166121a1565b34801561082757600080fd5b506102b16004803603604081101561083e57600080fd5b5080356001600160e01b03191690602001356001600160a01b03166121b3565b34801561086a57600080fd5b506105b0612279565b34801561087f57600080fd5b506102b16004803603606081101561089657600080fd5b506001600160a01b0381358116916020810135916040909101351661227f565b3480156108c257600080fd5b5061077e61249e565b3480156108d757600080fd5b506102b1600480360360c08110156108ee57600080fd5b60ff823516916020810135916040820135916060810135916001600160a01b03608083013516919081019060c0810160a0820135600160201b81111561093357600080fd5b82018360208201111561094557600080fd5b803590602001918460018302840111600160201b8311171561096657600080fd5b5090925090506124a3565b34801561097d57600080fd5b5061077e6004803603602081101561099457600080fd5b50356001600160e01b0319166127e6565b3480156109b157600080fd5b506102b1600480360360208110156109c857600080fd5b810190602081018135600160201b8111156109e257600080fd5b8201836020820111156109f457600080fd5b803590602001918460018302840111600160201b83111715610a1557600080fd5b509092509050612801565b348015610a2c57600080fd5b50610310600480360360a0811015610a4357600080fd5b6001600160a01b038235811692602081013590911691810190606081016040820135600160201b811115610a7657600080fd5b820183602082011115610a8857600080fd5b803590602001918460208302840111600160201b83111715610aa957600080fd5b919390929091602081019035600160201b811115610ac657600080fd5b820183602082011115610ad857600080fd5b803590602001918460208302840111600160201b83111715610af957600080fd5b919390929091602081019035600160201b811115610b1657600080fd5b820183602082011115610b2857600080fd5b803590602001918460018302840111600160201b83111715610b4957600080fd5b5090925090506128b1565b348015610b6057600080fd5b506102b160048036036040811015610b7757600080fd5b506001600160a01b0381351690602001356128c5565b348015610b9957600080fd5b506102b160048036036060811015610bb057600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b811115610bdf57600080fd5b820183602082011115610bf157600080fd5b803590602001918460018302840111600160201b83111715610c1257600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550612a68945050505050565b348015610c5f57600080fd5b50610569612a6d565b348015610c7457600080fd5b506102b160048036036040811015610c8b57600080fd5b81359190810190604081016020820135600160201b811115610cac57600080fd5b820183602082011115610cbe57600080fd5b803590602001918460208302840111600160201b83111715610cdf57600080fd5b509092509050612a75565b348015610cf657600080fd5b5061031060048036036060811015610d0d57600080fd5b6001600160a01b0382351691602081013591810190606081016040820135600160201b811115610d3c57600080fd5b820183602082011115610d4e57600080fd5b803590602001918460018302840111600160201b83111715610d6f57600080fd5b509092509050612b72565b348015610d8657600080fd5b50610310600480360360a0811015610d9d57600080fd5b6001600160a01b03823581169260208101359091169160408201359160608101359181019060a081016080820135600160201b811115610ddc57600080fd5b820183602082011115610dee57600080fd5b803590602001918460018302840111600160201b83111715610e0f57600080fd5b509092509050612b82565b348015610e2657600080fd5b50610e2f612b94565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610e69578181015183820152602001610e51565b50505050905090810190601f168015610e965780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60006001600160e01b031982166301ffc9a760e01b1480610ed557506001600160e01b03198216630a85bd0160e11b145b80610ef057506001600160e01b0319821663785cf2dd60e11b145b80610f0b57506001600160e01b0319821663607705c560e11b145b80610f2657506001600160e01b03198216630271189760e51b145b80610f4157506001600160e01b03198216630b135d3f60e11b145b15610f4e57506001610f75565b506001600160e01b031981166000908152600360205260409020546001600160a01b031615155b919050565b63607705c560e11b81565b630a85bd0160e11b949350505050565b600454600160a01b900460ff1615610ff4576040805162461bcd60e51b815260206004820152601f60248201527f6d757374206e6f7420616c726561647920626520696e697469616c697a656400604482015290519081900360640190fd5b6004805460ff60a01b1916600160a01b179055606061101284612bb5565b905060005b81518110156111e657600082828151811061102e57fe5b60200260200101519050836001600160a01b0316816001600160a01b031614156110895760405162461bcd60e51b8152600401808060200182810382526039815260200180612ef06039913960400191505060405180910390fd5b836001600160a01b0316856001600160a01b031614156110da5760405162461bcd60e51b815260040180806020018281038252602e815260200180612f29602e913960400191505060405180910390fd5b6001600160a01b03811661111f5760405162461bcd60e51b8152600401808060200182810382526026815260200180612ea86026913960400191505060405180910390fd5b6001600160a01b0385166111645760405162461bcd60e51b8152600401808060200182810382526022815260200180612ece6022913960400191505060405180910390fd5b600480546001600160a01b0319166001600160a01b0386811691909117909155600160a01b60008181559183169081018252600160209081526040928390208890558251918252810187905281517fb39b5f240c7440b58c1c6cfd328b09ff9aa18b3c8ef4b829774e4f5bad039416929181900390910190a150600101611017565b5050505050565b600454600160a01b900460ff1681565b60408051601960f81b6020808301919091526000602183018190523060601b602284015260368084018890528451808503909101815260569093019093528151910120611248612e1d565b611250612e1d565b611258612e1d565b6000806041881415611329576112ae60008a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff612c49169050565b60ff908116865290865281875284518651604080516000815260208181018084528d9052939094168482015260608401949094526080830152915160019260a0808401939192601f1981019281900390910190855afa158015611315573d6000803e3d6000fd5b5050506020604051035191508190506114cd565b60828814156114bd5761137c60008a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929392505063ffffffff612c49169050565b60ff16855285528552604080516020601f8b018190048102820181019092528981526113cf91604191908c908c9081908401838280828437600092019190915250929392505063ffffffff612c49169050565b60ff908116602087810191909152878101929092528188019290925284518751875160408051600081528086018083528d9052939095168386015260608301919091526080820152915160019260a08082019392601f1981019281900390910190855afa158015611444573d6000803e3d6000fd5b505060408051601f19808201516020808901518b8201518b830151600087528387018089528f905260ff909216868801526060860152608085015293519096506001945060a08084019493928201928290030190855afa1580156114ac573d6000803e3d6000fd5b5050506020604051035190506114cd565b5060009550611563945050505050565b6001600160a01b0382166114eb575060009550611563945050505050565b6001600160a01b038116611509575060009550611563945050505050565b806001600160a01b031660016000846001600160a01b0316600054018152602001908152602001600020546001600160a01b031614611552575060009550611563945050505050565b50630b135d3f60e11b955050505050505b9392505050565b600081565b60016020526000908152604090205481565b601b60ff88351614806115985750601c60ff883516145b6115e9576040805162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207369676e61747572652076657273696f6e20765b305d0000604482015290519081900360640190fd5b601b60ff60208901351614806116065750601c60ff602089013516145b611657576040805162461bcd60e51b815260206004820152601e60248201527f696e76616c6964207369676e61747572652076657273696f6e20765b315d0000604482015290519081900360640190fd5b604051601960f81b6020820181815260006021840181905230606081811b6022870152603686018a905288901b6bffffffffffffffffffffffff1916605686015290938492899189918991899190606a018383808284378083019250505097505050505050505060405160208183030381529060405280519060200120905060006001828a6000600281106116e857fe5b602002013560ff168a6000600281106116fd57fe5b604080516000815260208181018084529690965260ff90941684820152908402919091013560608301528a3560808301525160a08083019392601f198301929081900390910190855afa158015611758573d6000803e3d6000fd5b505060408051601f1980820151600080845260208085018087528990528f81013560ff16858701528e81013560608601528d81013560808601529451919650945060019360a0808501949193830192918290030190855afa1580156117c1573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038216611829576040805162461bcd60e51b815260206004820152601d60248201527f496e76616c6964207369676e617475726520666f72207369676e65722e000000604482015290519081900360640190fd5b6001600160a01b038116611884576040805162461bcd60e51b815260206004820152601f60248201527f496e76616c6964207369676e617475726520666f7220636f7369676e65722e00604482015290519081900360640190fd5b856001600160a01b0316826001600160a01b0316146118d45760405162461bcd60e51b8152600401808060200182810382526022815260200180612f576022913960400191505060405180910390fd5b6001600160a01b0382166000908152600260205260409020548711611940576040805162461bcd60e51b815260206004820152601f60248201527f6d757374207573652076616c6964206e6f6e636520666f72207369676e657200604482015290519081900360640190fd5b600080546001600160a01b0380851691820183526001602052604090922054918216148061197f5750816001600160a01b0316816001600160a01b0316145b6119c9576040805162461bcd60e51b815260206004820152601660248201527524b73b30b634b21030baba3437b934bd30ba34b7b71760511b604482015290519081900360640190fd5b6001600160a01b0383166000908152600260209081526040918290208a90558151601f8801829004820281018201909252868252611a239186918990899081908401838280828437600092019190915250612c6592505050565b5050505050505050505050565b600454600160a01b900460ff1615611a8f576040805162461bcd60e51b815260206004820152601f60248201527f6d757374206e6f7420616c726561647920626520696e697469616c697a656400604482015290519081900360640190fd5b6004805460ff60a01b1916600160a01b1790556001600160a01b038381169082161415611aed5760405162461bcd60e51b8152600401808060200182810382526039815260200180612ef06039913960400191505060405180910390fd5b806001600160a01b0316826001600160a01b03161415611b3e5760405162461bcd60e51b815260040180806020018281038252602e815260200180612f29602e913960400191505060405180910390fd5b6001600160a01b038316611b835760405162461bcd60e51b8152600401808060200182810382526026815260200180612ea86026913960400191505060405180910390fd5b6001600160a01b038216611bc85760405162461bcd60e51b8152600401808060200182810382526022815260200180612ece6022913960400191505060405180910390fd5b600480546001600160a01b0319166001600160a01b0383811691909117909155600160a01b60008181559185169081018252600160209081526040928390208590558251918252810184905281517fb39b5f240c7440b58c1c6cfd328b09ff9aa18b3c8ef4b829774e4f5bad039416929181900390910190a1505050565b333014611c9a576040805162461bcd60e51b815260206004820152601e60248201527f6d7573742062652063616c6c65642066726f6d2060696e766f6b652829600000604482015290519081900360640190fd5b600080546001600160a01b03838116909101825260016020526040909120541615611cf65760405162461bcd60e51b8152600401808060200182810382526039815260200180612e3c6039913960400191505060405180910390fd5b600480546001600160a01b038381166001600160a01b0319831617928390556040805192821680845293909116602083015280517f568ab3dedd6121f0385e007e641e74e1f49d0fa69cab2957b0b07c4c7de5abb69281900390910190a15050565b8460ff16601b1480611d6d57508460ff16601c145b611dbe576040805162461bcd60e51b815260206004820152601a60248201527f496e76616c6964207369676e61747572652076657273696f6e2e000000000000604482015290519081900360640190fd5b336000818152600260209081526040808320549051601960f81b9281018381526021820185905230606081811b60228501526036840185905287901b6056840152929585939287928a918a9190606a0183838082843780830192505050975050505050505050604051602081830303815290604052805190602001209050600060018289898960405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa158015611e9b573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116611ef8576040805162461bcd60e51b815260206004820152601260248201527124b73b30b634b21039b4b3b730ba3ab9329760711b604482015290519081900360640190fd5b6000805433018152600160205260409020546001600160a01b038181169083161480611f2c57506001600160a01b03811633145b611f76576040805162461bcd60e51b815260206004820152601660248201527524b73b30b634b21030baba3437b934bd30ba34b7b71760511b604482015290519081900360640190fd5b336000908152600260209081526040918290206001870190558151601f8801829004820281018201909252868252611fca9185918990899081908401838280828437600092019190915250612c6592505050565b505050505050505050565b6004546001600160a01b031681565b6004546001600160a01b03163314612043576040805162461bcd60e51b815260206004820152601f60248201527f73656e646572206d757374206265207265636f76657279206164647265737300604482015290519081900360640190fd5b6001600160a01b0382166120885760405162461bcd60e51b8152600401808060200182810382526026815260200180612ea86026913960400191505060405180910390fd5b6004546001600160a01b03838116911614156120d55760405162461bcd60e51b8152600401808060200182810382526039815260200180612ef06039913960400191505060405180910390fd5b6001600160a01b038116612130576040805162461bcd60e51b815260206004820152601e60248201527f54686520636f7369676e6572206d757374206e6f74206265207a65726f2e0000604482015290519081900360640190fd5b60008054600160a01b81810183556001600160a01b038516918201018252600160209081526040928390208490558251918252810183905281517fa9364fb2836862098c2b593d2d3f46759b4c6d5b054300f96172b0394430008a929181900390910190a15050565b600160a01b81565b60026020526000908152604090205481565b333014612207576040805162461bcd60e51b815260206004820152601e60248201527f6d7573742062652063616c6c65642066726f6d2060696e766f6b652829600000604482015290519081900360640190fd5b6001600160e01b0319821660008181526003602090815260409182902080546001600160a01b0319166001600160a01b03861690811790915582519384529083015280517fd09b01a1a877e1a97b048725e0697d9be07bb94320c536e72b976c81016891fb9281900390910190a15050565b60005481565b6004546001600160a01b031633146122de576040805162461bcd60e51b815260206004820152601f60248201527f73656e646572206d757374206265207265636f76657279206164647265737300604482015290519081900360640190fd5b6001600160a01b0383166123235760405162461bcd60e51b8152600401808060200182810382526026815260200180612ea86026913960400191505060405180910390fd5b806001600160a01b0316836001600160a01b031614156123745760405162461bcd60e51b8152600401808060200182810382526039815260200180612ef06039913960400191505060405180910390fd5b6001600160a01b0382166123cf576040805162461bcd60e51b815260206004820152601e60248201527f54686520636f7369676e6572206d757374206e6f74206265207a65726f2e0000604482015290519081900360640190fd5b60008054600160a01b81810183556001600160a01b0380871690920101825260016020908152604092839020859055600480548584166001600160a01b03198216179182905584519084168082529190931691830191909152825190927f568ab3dedd6121f0385e007e641e74e1f49d0fa69cab2957b0b07c4c7de5abb6928290030190a1604080516001600160a01b03861681526020810185905281517fa9364fb2836862098c2b593d2d3f46759b4c6d5b054300f96172b0394430008a929181900390910190a150505050565b600181565b8660ff16601b14806124b857508660ff16601c145b612509576040805162461bcd60e51b815260206004820152601a60248201527f496e76616c6964207369676e61747572652076657273696f6e2e000000000000604482015290519081900360640190fd5b604051601960f81b6020820181815260006021840181905230606081811b6022870152603686018a905288901b6bffffffffffffffffffffffff1916605686015290938492899189918991899190606a018383808284378083019250505097505050505050505060405160208183030381529060405280519060200120905060006001828a8a8a60405160008152602001604052604051808581526020018460ff1660ff1681526020018381526020018281526020019450505050506020604051602081039080840390855afa1580156125e7573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116612644576040805162461bcd60e51b815260206004820152601260248201527124b73b30b634b21039b4b3b730ba3ab9329760711b604482015290519081900360640190fd5b6001600160a01b03811660009081526002602052604090205486116126b0576040805162461bcd60e51b815260206004820152601f60248201527f6d757374207573652076616c6964206e6f6e636520666f72207369676e657200604482015290519081900360640190fd5b846001600160a01b0316816001600160a01b0316146127005760405162461bcd60e51b8152600401808060200182810382526022815260200180612f576022913960400191505060405180910390fd5b600080546001600160a01b0380841691820183526001602052604090922054918216148061273657506001600160a01b03811633145b612780576040805162461bcd60e51b815260206004820152601660248201527524b73b30b634b21030baba3437b934bd30ba34b7b71760511b604482015290519081900360640190fd5b6001600160a01b0382166000908152600260209081526040918290208990558151601f87018290048202810182019092528582526127da9185918890889081908401838280828437600092019190915250612c6592505050565b50505050505050505050565b6003602052600090815260409020546001600160a01b031681565b6000805433908101825260016020526040909120546001600160a01b03161461286a576040805162461bcd60e51b815260206004820152601660248201527524b73b30b634b21030baba3437b934bd30ba34b7b71760511b604482015290519081900360640190fd5b6128ad6000801b83838080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250612c6592505050565b5050565b63bc197c8160e01b98975050505050505050565b333014612919576040805162461bcd60e51b815260206004820152601e60248201527f6d7573742062652063616c6c65642066726f6d2060696e766f6b652829600000604482015290519081900360640190fd5b6001600160a01b03821661295e5760405162461bcd60e51b8152600401808060200182810382526026815260200180612ea86026913960400191505060405180910390fd5b6004546001600160a01b03838116911614156129ab5760405162461bcd60e51b8152600401808060200182810382526039815260200180612ef06039913960400191505060405180910390fd5b6001600160a01b03811615806129cf57506004546001600160a01b03828116911614155b612a0a5760405162461bcd60e51b815260040180806020018281038252602e815260200180612f29602e913960400191505060405180910390fd5b600080546001600160a01b0384169081018252600160209081526040928390208490558251918252810183905281517fb39b5f240c7440b58c1c6cfd328b09ff9aa18b3c8ef4b829774e4f5bad039416929181900390910190a15050565b505050565b601960f81b81565b600083118015612a88575063ffffffff83105b612ad9576040805162461bcd60e51b815260206004820152601760248201527f496e76616c69642076657273696f6e206e756d6265722e000000000000000000604482015290519081900360640190fd5b60005460a084901b908110612b1f5760405162461bcd60e51b8152600401808060200182810382526033815260200180612e756033913960400191505060405180910390fd5b60005b828110156111e65760016000858584818110612b3a57fe5b905060200201356001600160a01b03166001600160a01b03168401815260200190815260200160002060009055806001019050612b22565b63785cf2dd60e11b949350505050565b63f23a6e6160e01b9695505050505050565b604051806040016040528060058152602001640312e312e360dc1b81525081565b60606014825181612bc257fe5b04604051908082528060200260200182016040528015612bec578160200160208202803883390190505b50905060005b8251811015612c4357600080826014019050808501519150818460148581612c1657fe5b0481518110612c2157fe5b6001600160a01b03909216602092830291909101909101525050601401612bf2565b50919050565b0160208101516040820151606090920151909260009190911a90565b60008060606040518060400160405280601481526020017311185d1848199a595b19081d1bdbc81cda1bdc9d60621b815250905060606040518060400160405280600b81526020016a10d85b1b0819985a5b195960aa1b81525090506055855110158290612d515760405162461bcd60e51b81526004018080602001828103825283818151815260200191508051906020019080838360005b83811015612d16578181015183820152602001612cfe565b50505050905090810190601f168015612d435780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060208501805160001a865182016001830192505b80831015612dd157603483015160548401810182811115612d8957865160208801fd5b60008083605488016014890151895160601c5af1612dc1578360018114612db7578960020a89179850612dbf565b865160208801fd5b505b6001890198508094505050612d66565b5050604080518881526020810186905280820187905290517f101214446435ebbb29893f3348e3aae5ea070b63037a3df346d09d3396a34aee92509081900360600190a1505050505050565b6040518060400160405280600290602082028038833950919291505056fe446f206e6f742075736520616e20617574686f72697a6564206164647265737320617320746865207265636f7665727920616464726573732e596f752063616e206f6e6c79207265636f766572206761732066726f6d2065787069726564206175746856657273696f6e732e417574686f72697a656420616464726573736573206d757374206e6f74206265207a65726f2e496e697469616c20636f7369676e6572206d757374206e6f74206265207a65726f2e446f206e6f742075736520746865207265636f76657279206164647265737320617320616e20617574686f72697a656420616464726573732e446f206e6f742075736520746865207265636f766572792061646472657373206173206120636f7369676e65722e617574686f72697a656420616464726573736573206d75737420626520657175616ca265627a7a723058202bf5771700693f16c2ca90585279bc0b2313fd2ebde70ff6d3e41bd74a5838a964736f6c634300050a0032417574686f72697a656420616464726573736573206d757374206e6f74206265207a65726f2e496e697469616c20636f7369676e6572206d757374206e6f74206265207a65726f2e446f206e6f742075736520746865207265636f76657279206164647265737320617320616e20617574686f72697a656420616464726573732e446f206e6f742075736520746865207265636f766572792061646472657373206173206120636f7369676e65722e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000';
-}
-
-// File: contracts/WalletFactory/WalletFactory.sol
-
-pragma solidity ^0.5.10;
-
-
-
-
-
-
-/// @title WalletFactory
-/// @dev A contract for creating wallets.
-contract WalletFactory is FullWalletByteCode, HasNoEther, CloneFactory {
-
- /// @dev Pointer to a pre-deployed instance of the Wallet contract. This
- /// deployment contains all the Wallet code.
- address public cloneWalletAddress;
-
- /// @notice Emitted whenever a wallet is created
- /// @param wallet The address of the wallet created
- /// @param authorizedAddress The initial authorized address of the wallet
- /// @param full `true` if the deployed wallet was a full, self
- /// contained wallet; `false` if the wallet is a clone wallet
- event WalletCreated(address wallet, address authorizedAddress, bool full);
-
- constructor(address _cloneWalletAddress) public {
- cloneWalletAddress = _cloneWalletAddress;
- }
-
- /// @notice Used to deploy a wallet clone
- /// @dev Reasonably cheap to run (~100K gas)
- /// @param _recoveryAddress the initial recovery address for the wallet
- /// @param _authorizedAddress an initial authorized address for the wallet
- /// @param _cosigner the cosigning address for the initial `_authorizedAddress`
- function deployCloneWallet(
- address _recoveryAddress,
- address _authorizedAddress,
- uint256 _cosigner
- )
- public
- {
- // create the clone
- address payable clone = createClone(cloneWalletAddress);
- // init the clone
- CloneableWallet(clone).init(_authorizedAddress, _cosigner, _recoveryAddress);
- // emit event
- emit WalletCreated(clone, _authorizedAddress, false);
- }
-
- /// @notice Used to deploy a wallet clone
- /// @dev Reasonably cheap to run (~100K gas)
- /// @dev The clone does not require `onlyOwner` as we avoid front-running
- /// attacks by hashing the salt combined with the call arguments and using
- /// that as the salt we provide to `create2`. Given this constraint, a
- /// front-runner would need to use the same `_recoveryAddress`, `_authorizedAddress`,
- /// and `_cosigner` parameters as the original deployer, so the original deployer
- /// would have control of the wallet even if the transaction was front-run.
- /// @param _recoveryAddress the initial recovery address for the wallet
- /// @param _authorizedAddress an initial authorized address for the wallet
- /// @param _cosigner the cosigning address for the initial `_authorizedAddress`
- /// @param _salt the salt for the `create2` instruction
- function deployCloneWallet2(
- address _recoveryAddress,
- address _authorizedAddress,
- uint256 _cosigner,
- bytes32 _salt
- )
- public
- {
- // calculate our own salt based off of args
- bytes32 salt = keccak256(abi.encodePacked(_salt, _authorizedAddress, _cosigner, _recoveryAddress));
- // create the clone counterfactually
- address payable clone = createClone2(cloneWalletAddress, salt);
- // ensure we get an address
- require(clone != address(0), "wallet must have address");
-
- // check size
- uint256 size;
- // note this takes an additional 700 gas
- assembly {
- size := extcodesize(clone)
- }
-
- require(size > 0, "wallet must have code");
-
- // init the clone
- CloneableWallet(clone).init(_authorizedAddress, _cosigner, _recoveryAddress);
- // emit event
- emit WalletCreated(clone, _authorizedAddress, false);
- }
-
- function deployCloneWallet2WithMultiAuthorizedAddress(
- address _recoveryAddress,
- bytes memory _authorizedAddresses,
- uint256 _cosigner,
- bytes32 _salt
- )
- public
- {
- require(_authorizedAddresses.length / 20 > 0 && _authorizedAddresses.length % 20 == 0, "invalid address byte array");
- address[] memory addresses = bytesToAddresses(_authorizedAddresses);
-
- // calculate our own salt based off of args
- bytes32 salt = keccak256(abi.encodePacked(_salt, addresses[0], _cosigner, _recoveryAddress));
- // create the clone counterfactually
- address payable clone = createClone2(cloneWalletAddress, salt);
- // ensure we get an address
- require(clone != address(0), "wallet must have address");
-
- // check size
- uint256 size;
- // note this takes an additional 700 gas
- assembly {
- size := extcodesize(clone)
- }
-
- require(size > 0, "wallet must have code");
-
- // init the clone
- CloneableWallet(clone).init2(_authorizedAddresses, _cosigner, _recoveryAddress);
- // emit event
- emit WalletCreated(clone, addresses[0], false);
- }
-
- function bytesToAddresses(bytes memory bys) private pure returns (address[] memory addresses) {
- addresses = new address[](bys.length/20);
- for (uint i=0; i < bys.length; i+=20) {
- address addr;
- uint end = i+20;
- assembly {
- addr := mload(add(bys,end))
- }
- addresses[i/20] = addr;
- }
- }
-
- /// @notice Used to deploy a full wallet
- /// @dev This is potentially very gas intensive!
- /// @param _recoveryAddress The initial recovery address for the wallet
- /// @param _authorizedAddress An initial authorized address for the wallet
- /// @param _cosigner The cosigning address for the initial `_authorizedAddress`
- function deployFullWallet(
- address _recoveryAddress,
- address _authorizedAddress,
- uint256 _cosigner
- )
- public
- {
- // Copy the bytecode of the full wallet to memory.
- bytes memory fullWallet = fullWalletBytecode;
-
- address full;
- assembly {
- // get start of wallet buffer
- let startPtr := add(fullWallet, 0x20)
- // get start of arguments
- let endPtr := sub(add(startPtr, mload(fullWallet)), 0x60)
- // copy constructor parameters to memory
- mstore(endPtr, _authorizedAddress)
- mstore(add(endPtr, 0x20), _cosigner)
- mstore(add(endPtr, 0x40), _recoveryAddress)
- // create the contract
- full := create(0, startPtr, mload(fullWallet))
- }
-
- // check address
- require(full != address(0), "wallet must have address");
-
- // check size
- uint256 size;
- // note this takes an additional 700 gas,
- // which is a relatively small amount in this case
- assembly {
- size := extcodesize(full)
- }
-
- require(size > 0, "wallet must have code");
-
- emit WalletCreated(full, _authorizedAddress, true);
- }
-
- /// @notice Used to deploy a full wallet counterfactually
- /// @dev This is potentially very gas intensive!
- /// @dev As the arguments are appended to the end of the bytecode and
- /// then included in the `create2` call, we are safe from front running
- /// attacks and do not need to restrict the caller of this function.
- /// @param _recoveryAddress The initial recovery address for the wallet
- /// @param _authorizedAddress An initial authorized address for the wallet
- /// @param _cosigner The cosigning address for the initial `_authorizedAddress`
- /// @param _salt The salt for the `create2` instruction
- function deployFullWallet2(
- address _recoveryAddress,
- address _authorizedAddress,
- uint256 _cosigner,
- bytes32 _salt
- )
- public
- {
- // Note: Be sure to update this whenever the wallet bytecode changes!
- // Simply run `yarn run build` and then copy the `"bytecode"`
- // portion from the `build/contracts/FullWallet.json` file to here,
- // then append 64x3 0's.
- //
- // Note: By not passing in the code as an argument, we save 600,000 gas.
- // An alternative would be to use `extcodecopy`, but again we save
- // gas by not having to call `extcodecopy`.
- bytes memory fullWallet = fullWalletBytecode;
-
- address full;
- assembly {
- // get start of wallet buffer
- let startPtr := add(fullWallet, 0x20)
- // get start of arguments
- let endPtr := sub(add(startPtr, mload(fullWallet)), 0x60)
- // copy constructor parameters to memory
- mstore(endPtr, _authorizedAddress)
- mstore(add(endPtr, 0x20), _cosigner)
- mstore(add(endPtr, 0x40), _recoveryAddress)
- // create the contract using create2
- full := create2(0, startPtr, mload(fullWallet), _salt)
- }
-
- // check address
- require(full != address(0), "wallet must have address");
-
- // check size
- uint256 size;
- // note this takes an additional 700 gas,
- // which is a relatively small amount in this case
- assembly {
- size := extcodesize(full)
- }
-
- require(size > 0, "wallet must have code");
-
- emit WalletCreated(full, _authorizedAddress, true);
- }
-}
\ No newline at end of file
diff --git a/example/errors/Contract1928.sol b/example/errors/Contract1928.sol
deleted file mode 100644
index e802ec7..0000000
--- a/example/errors/Contract1928.sol
+++ /dev/null
@@ -1,1272 +0,0 @@
-pragma solidity ^0.4.11;
-
-// NB: this is the newer ERC20 returning bool, need different book contract for older style tokens
-contract ERC20 {
- function totalSupply() constant returns (uint);
- function balanceOf(address _owner) constant returns (uint balance);
- function transfer(address _to, uint _value) returns (bool success);
- function transferFrom(address _from, address _to, uint _value) returns (bool success);
- function approve(address _spender, uint _value) returns (bool success);
- function allowance(address _owner, address _spender) constant returns (uint remaining);
- event Transfer(address indexed _from, address indexed _to, uint _value);
- event Approval(address indexed _owner, address indexed _spender, uint _value);
-}
-
-// UbiTok.io on-chain continuous limit order book matching engine.
-// This variation is for a "nice" ERC20 token as base, ETH as quoted, and standard fees with reward token.
-// Copyright (c) Bonnag Limited. All Rights Reserved.
-// Version 1.1.0y - variant with totalsupply validation disabled
-// This contract allows minPriceExponent, baseMinInitialSize, and baseMinRemainingSize
-// to be set at init() time appropriately for the token decimals and likely value.
-//
-//
-contract BookERC20EthV1p1y {
-
- enum BookType {
- ERC20EthV1
- }
-
- enum Direction {
- Invalid,
- Buy,
- Sell
- }
-
- enum Status {
- Unknown,
- Rejected,
- Open,
- Done,
- NeedsGas,
- Sending, // not used by contract - web only
- FailedSend, // not used by contract - web only
- FailedTxn // not used by contract - web only
- }
-
- enum ReasonCode {
- None,
- InvalidPrice,
- InvalidSize,
- InvalidTerms,
- InsufficientFunds,
- WouldTake,
- Unmatched,
- TooManyMatches,
- ClientCancel
- }
-
- enum Terms {
- GTCNoGasTopup,
- GTCWithGasTopup,
- ImmediateOrCancel,
- MakerOnly
- }
-
- struct Order {
- // these are immutable once placed:
-
- address client;
- uint16 price; // packed representation of side + price
- uint sizeBase;
- Terms terms;
-
- // these are mutable until Done or Rejected:
-
- Status status;
- ReasonCode reasonCode;
- uint128 executedBase; // gross amount executed in base currency (before fee deduction)
- uint128 executedCntr; // gross amount executed in counter currency (before fee deduction)
- uint128 feesBaseOrCntr; // base for buy, cntr for sell
- uint128 feesRwrd;
- }
-
- struct OrderChain {
- uint128 firstOrderId;
- uint128 lastOrderId;
- }
-
- struct OrderChainNode {
- uint128 nextOrderId;
- uint128 prevOrderId;
- }
-
- // It should be possible to reconstruct the expected state of the contract given:
- // - ClientPaymentEvent log history
- // - ClientOrderEvent log history
- // - Calling getOrder for the other immutable order fields of orders referenced by ClientOrderEvent
-
- enum ClientPaymentEventType {
- Deposit,
- Withdraw,
- TransferFrom,
- Transfer
- }
-
- enum BalanceType {
- Base,
- Cntr,
- Rwrd
- }
-
- event ClientPaymentEvent(
- address indexed client,
- ClientPaymentEventType clientPaymentEventType,
- BalanceType balanceType,
- int clientBalanceDelta
- );
-
- enum ClientOrderEventType {
- Create,
- Continue,
- Cancel
- }
-
- event ClientOrderEvent(
- address indexed client,
- ClientOrderEventType clientOrderEventType,
- uint128 orderId,
- uint maxMatches
- );
-
- enum MarketOrderEventType {
- // orderCount++, depth += depthBase
- Add,
- // orderCount--, depth -= depthBase
- Remove,
- // orderCount--, depth -= depthBase, traded += tradeBase
- // (depth change and traded change differ when tiny remaining amount refunded)
- CompleteFill,
- // orderCount unchanged, depth -= depthBase, traded += tradeBase
- PartialFill
- }
-
- // Technically not needed but these events can be used to maintain an order book or
- // watch for fills. Note that the orderId and price are those of the maker.
-
- event MarketOrderEvent(
- uint256 indexed eventTimestamp,
- uint128 indexed orderId,
- MarketOrderEventType marketOrderEventType,
- uint16 price,
- uint depthBase,
- uint tradeBase
- );
-
- // the base token (e.g. TEST)
-
- ERC20 baseToken;
-
- // minimum order size (inclusive)
- uint baseMinInitialSize; // set at init
-
- // if following partial match, the remaning gets smaller than this, remove from book and refund:
- // generally we make this 10% of baseMinInitialSize
- uint baseMinRemainingSize; // set at init
-
- // maximum order size (exclusive)
- // chosen so that even multiplied by the max price (or divided by the min price),
- // and then multiplied by ethRwrdRate, it still fits in 2^127, allowing us to save
- // some gas by storing executed + fee fields as uint128.
- // even with 18 decimals, this still allows order sizes up to 1,000,000,000.
- // if we encounter a token with e.g. 36 decimals we'll have to revisit ...
- uint constant baseMaxSize = 10 ** 30;
-
- // the counter currency (ETH)
- // (no address because it is ETH)
-
- // avoid the book getting cluttered up with tiny amounts not worth the gas
- uint constant cntrMinInitialSize = 10 finney;
-
- // see comments for baseMaxSize
- uint constant cntrMaxSize = 10 ** 30;
-
- // the reward token that can be used to pay fees (UBI)
-
- ERC20 rwrdToken; // set at init
-
- // used to convert ETH amount to reward tokens when paying fee with reward tokens
- uint constant ethRwrdRate = 1000;
-
- // funds that belong to clients (base, counter, and reward)
-
- mapping (address => uint) balanceBaseForClient;
- mapping (address => uint) balanceCntrForClient;
- mapping (address => uint) balanceRwrdForClient;
-
- // fee charged on liquidity taken, expressed as a divisor
- // (e.g. 2000 means 1/2000, or 0.05%)
-
- uint constant feeDivisor = 2000;
-
- // fees charged are given to:
-
- address feeCollector; // set at init
-
- // all orders ever created
-
- mapping (uint128 => Order) orderForOrderId;
-
- // Effectively a compact mapping from price to whether there are any open orders at that price.
- // See "Price Calculation Constants" below as to why 85.
-
- uint256[85] occupiedPriceBitmaps;
-
- // These allow us to walk over the orders in the book at a given price level (and add more).
-
- mapping (uint16 => OrderChain) orderChainForOccupiedPrice;
- mapping (uint128 => OrderChainNode) orderChainNodeForOpenOrderId;
-
- // These allow a client to (reasonably) efficiently find their own orders
- // without relying on events (which even indexed are a bit expensive to search
- // and cannot be accessed from smart contracts). See walkOrders.
-
- mapping (address => uint128) mostRecentOrderIdForClient;
- mapping (uint128 => uint128) clientPreviousOrderIdBeforeOrderId;
-
- // Price Calculation Constants.
- //
- // We pack direction and price into a crafty decimal floating point representation
- // for efficient indexing by price, the main thing we lose by doing so is precision -
- // we only have 3 significant figures in our prices.
- //
- // An unpacked price consists of:
- //
- // direction - invalid / buy / sell
- // mantissa - ranges from 100 to 999 representing 0.100 to 0.999
- // exponent - ranges from minimumPriceExponent to minimumPriceExponent + 11
- // (e.g. -5 to +6 for a typical pair where minPriceExponent = -5)
- //
- // The packed representation has 21601 different price values:
- //
- // 0 = invalid (can be used as marker value)
- // 1 = buy at maximum price (0.999 * 10 ** 6)
- // ... = other buy prices in descending order
- // 5400 = buy at 1.00
- // ... = other buy prices in descending order
- // 10800 = buy at minimum price (0.100 * 10 ** -5)
- // 10801 = sell at minimum price (0.100 * 10 ** -5)
- // ... = other sell prices in descending order
- // 16201 = sell at 1.00
- // ... = other sell prices in descending order
- // 21600 = sell at maximum price (0.999 * 10 ** 6)
- // 21601+ = do not use
- //
- // If we want to map each packed price to a boolean value (which we do),
- // we require 85 256-bit words. Or 42.5 for each side of the book.
-
- int8 minPriceExponent; // set at init
-
- uint constant invalidPrice = 0;
-
- // careful: max = largest unpacked value, not largest packed value
- uint constant maxBuyPrice = 1;
- uint constant minBuyPrice = 10800;
- uint constant minSellPrice = 10801;
- uint constant maxSellPrice = 21600;
-
- // Constructor.
- //
- // Sets feeCollector to the creator. Creator needs to call init() to finish setup.
- //
- function BookERC20EthV1p1y() {
- address creator = msg.sender;
- feeCollector = creator;
- }
-
- // "Public" Management - set address of base and reward tokens.
- //
- // Can only be done once (normally immediately after creation) by the fee collector.
- //
- // Used instead of a constructor to make deployment easier.
- //
- // baseMinInitialSize is the minimum order size in token-wei;
- // the minimum resting size will be one tenth of that.
- //
- // minPriceExponent controls the range of prices supported by the contract;
- // the range will be 0.100*10**minPriceExponent to 0.999*10**(minPriceExponent + 11)
- // but careful; this is in token-wei : wei, ignoring the number of decimals of the token
- // e.g. -5 implies 1 token-wei worth between 0.100e-5 to 0.999e+6 wei
- // which implies same token:eth exchange rate if token decimals are 18 like eth,
- // but if token decimals are 8, that would imply 1 token worth 10 wei to 0.000999 ETH.
- //
- function init(ERC20 _baseToken, ERC20 _rwrdToken, uint _baseMinInitialSize, int8 _minPriceExponent) public {
- require(msg.sender == feeCollector);
- require(address(baseToken) == 0);
- require(address(_baseToken) != 0);
- require(address(rwrdToken) == 0);
- require(address(_rwrdToken) != 0);
- require(_baseMinInitialSize >= 10);
- require(_baseMinInitialSize < baseMaxSize / 1000000);
- require(_minPriceExponent >= -20 && _minPriceExponent <= 20);
- if (_minPriceExponent < 2) {
- require(_baseMinInitialSize >= 10 ** uint(3-int(minPriceExponent)));
- }
- baseMinInitialSize = _baseMinInitialSize;
- // dust prevention. truncation ok, know >= 10
- baseMinRemainingSize = _baseMinInitialSize / 10;
- minPriceExponent = _minPriceExponent;
- // attempt to catch bad tokens (disabled for YOLO)
- //require(_baseToken.totalSupply() > 0);
- baseToken = _baseToken;
- require(_rwrdToken.totalSupply() > 0);
- rwrdToken = _rwrdToken;
- }
-
- // "Public" Management - change fee collector
- //
- // The new fee collector only gets fees charged after this point.
- //
- function changeFeeCollector(address newFeeCollector) public {
- address oldFeeCollector = feeCollector;
- require(msg.sender == oldFeeCollector);
- require(newFeeCollector != oldFeeCollector);
- feeCollector = newFeeCollector;
- }
-
- // Public Info View - what is being traded here, what are the limits?
- //
- function getBookInfo() public constant returns (
- BookType _bookType, address _baseToken, address _rwrdToken,
- uint _baseMinInitialSize, uint _cntrMinInitialSize, int8 _minPriceExponent,
- uint _feeDivisor, address _feeCollector
- ) {
- return (
- BookType.ERC20EthV1,
- address(baseToken),
- address(rwrdToken),
- baseMinInitialSize, // can assume min resting size is one tenth of this
- cntrMinInitialSize,
- minPriceExponent,
- feeDivisor,
- feeCollector
- );
- }
-
- // Public Funds View - get balances held by contract on behalf of the client,
- // or balances approved for deposit but not yet claimed by the contract.
- //
- // Excludes funds in open orders.
- //
- // Helps a web ui get a consistent snapshot of balances.
- //
- // It would be nice to return the off-exchange ETH balance too but there's a
- // bizarre bug in geth (and apparently as a result via MetaMask) that leads
- // to unpredictable behaviour when looking up client balances in constant
- // functions - see e.g. https://github.com/ethereum/solidity/issues/2325 .
- //
- function getClientBalances(address client) public constant returns (
- uint bookBalanceBase,
- uint bookBalanceCntr,
- uint bookBalanceRwrd,
- uint approvedBalanceBase,
- uint approvedBalanceRwrd,
- uint ownBalanceBase,
- uint ownBalanceRwrd
- ) {
- bookBalanceBase = balanceBaseForClient[client];
- bookBalanceCntr = balanceCntrForClient[client];
- bookBalanceRwrd = balanceRwrdForClient[client];
- approvedBalanceBase = baseToken.allowance(client, address(this));
- approvedBalanceRwrd = rwrdToken.allowance(client, address(this));
- ownBalanceBase = baseToken.balanceOf(client);
- ownBalanceRwrd = rwrdToken.balanceOf(client);
- }
-
- // Public Funds Manipulation - deposit previously-approved base tokens.
- //
- function transferFromBase() public {
- address client = msg.sender;
- address book = address(this);
- // we trust the ERC20 token contract not to do nasty things like call back into us -
- // if we cannot trust the token then why are we allowing it to be traded?
- uint amountBase = baseToken.allowance(client, book);
- require(amountBase > 0);
- // NB: needs change for older ERC20 tokens that don't return bool
- require(baseToken.transferFrom(client, book, amountBase));
- // belt and braces
- assert(baseToken.allowance(client, book) == 0);
- balanceBaseForClient[client] += amountBase;
- ClientPaymentEvent(client, ClientPaymentEventType.TransferFrom, BalanceType.Base, int(amountBase));
- }
-
- // Public Funds Manipulation - withdraw base tokens (as a transfer).
- //
- function transferBase(uint amountBase) public {
- address client = msg.sender;
- require(amountBase > 0);
- require(amountBase <= balanceBaseForClient[client]);
- // overflow safe since we checked less than balance above
- balanceBaseForClient[client] -= amountBase;
- // we trust the ERC20 token contract not to do nasty things like call back into us -
- // if we cannot trust the token then why are we allowing it to be traded?
- // NB: needs change for older ERC20 tokens that don't return bool
- require(baseToken.transfer(client, amountBase));
- ClientPaymentEvent(client, ClientPaymentEventType.Transfer, BalanceType.Base, -int(amountBase));
- }
-
- // Public Funds Manipulation - deposit counter currency (ETH).
- //
- function depositCntr() public payable {
- address client = msg.sender;
- uint amountCntr = msg.value;
- require(amountCntr > 0);
- // overflow safe - if someone owns pow(2,255) ETH we have bigger problems
- balanceCntrForClient[client] += amountCntr;
- ClientPaymentEvent(client, ClientPaymentEventType.Deposit, BalanceType.Cntr, int(amountCntr));
- }
-
- // Public Funds Manipulation - withdraw counter currency (ETH).
- //
- function withdrawCntr(uint amountCntr) public {
- address client = msg.sender;
- require(amountCntr > 0);
- require(amountCntr <= balanceCntrForClient[client]);
- // overflow safe - checked less than balance above
- balanceCntrForClient[client] -= amountCntr;
- // safe - not enough gas to do anything interesting in fallback, already adjusted balance
- client.transfer(amountCntr);
- ClientPaymentEvent(client, ClientPaymentEventType.Withdraw, BalanceType.Cntr, -int(amountCntr));
- }
-
- // Public Funds Manipulation - deposit previously-approved reward tokens.
- //
- function transferFromRwrd() public {
- address client = msg.sender;
- address book = address(this);
- uint amountRwrd = rwrdToken.allowance(client, book);
- require(amountRwrd > 0);
- // we wrote the reward token so we know it supports ERC20 properly and is not evil
- require(rwrdToken.transferFrom(client, book, amountRwrd));
- // belt and braces
- assert(rwrdToken.allowance(client, book) == 0);
- balanceRwrdForClient[client] += amountRwrd;
- ClientPaymentEvent(client, ClientPaymentEventType.TransferFrom, BalanceType.Rwrd, int(amountRwrd));
- }
-
- // Public Funds Manipulation - withdraw base tokens (as a transfer).
- //
- function transferRwrd(uint amountRwrd) public {
- address client = msg.sender;
- require(amountRwrd > 0);
- require(amountRwrd <= balanceRwrdForClient[client]);
- // overflow safe - checked less than balance above
- balanceRwrdForClient[client] -= amountRwrd;
- // we wrote the reward token so we know it supports ERC20 properly and is not evil
- require(rwrdToken.transfer(client, amountRwrd));
- ClientPaymentEvent(client, ClientPaymentEventType.Transfer, BalanceType.Rwrd, -int(amountRwrd));
- }
-
- // Public Order View - get full details of an order.
- //
- // If the orderId does not exist, status will be Unknown.
- //
- function getOrder(uint128 orderId) public constant returns (
- address client, uint16 price, uint sizeBase, Terms terms,
- Status status, ReasonCode reasonCode, uint executedBase, uint executedCntr,
- uint feesBaseOrCntr, uint feesRwrd) {
- Order storage order = orderForOrderId[orderId];
- return (order.client, order.price, order.sizeBase, order.terms,
- order.status, order.reasonCode, order.executedBase, order.executedCntr,
- order.feesBaseOrCntr, order.feesRwrd);
- }
-
- // Public Order View - get mutable details of an order.
- //
- // If the orderId does not exist, status will be Unknown.
- //
- function getOrderState(uint128 orderId) public constant returns (
- Status status, ReasonCode reasonCode, uint executedBase, uint executedCntr,
- uint feesBaseOrCntr, uint feesRwrd) {
- Order storage order = orderForOrderId[orderId];
- return (order.status, order.reasonCode, order.executedBase, order.executedCntr,
- order.feesBaseOrCntr, order.feesRwrd);
- }
-
- // Public Order View - enumerate all recent orders + all open orders for one client.
- //
- // Not really designed for use from a smart contract transaction.
- //
- // Idea is:
- // - client ensures order ids are generated so that most-signficant part is time-based;
- // - client decides they want all orders after a certain point-in-time,
- // and chooses minClosedOrderIdCutoff accordingly;
- // - before that point-in-time they just get open and needs gas orders
- // - client calls walkClientOrders with maybeLastOrderIdReturned = 0 initially;
- // - then repeats with the orderId returned by walkClientOrders;
- // - (and stops if it returns a zero orderId);
- //
- // Note that client is only used when maybeLastOrderIdReturned = 0.
- //
- function walkClientOrders(
- address client, uint128 maybeLastOrderIdReturned, uint128 minClosedOrderIdCutoff
- ) public constant returns (
- uint128 orderId, uint16 price, uint sizeBase, Terms terms,
- Status status, ReasonCode reasonCode, uint executedBase, uint executedCntr,
- uint feesBaseOrCntr, uint feesRwrd) {
- if (maybeLastOrderIdReturned == 0) {
- orderId = mostRecentOrderIdForClient[client];
- } else {
- orderId = clientPreviousOrderIdBeforeOrderId[maybeLastOrderIdReturned];
- }
- while (true) {
- if (orderId == 0) return;
- Order storage order = orderForOrderId[orderId];
- if (orderId >= minClosedOrderIdCutoff) break;
- if (order.status == Status.Open || order.status == Status.NeedsGas) break;
- orderId = clientPreviousOrderIdBeforeOrderId[orderId];
- }
- return (orderId, order.price, order.sizeBase, order.terms,
- order.status, order.reasonCode, order.executedBase, order.executedCntr,
- order.feesBaseOrCntr, order.feesRwrd);
- }
-
- // Internal Price Calculation - turn packed price into a friendlier unpacked price.
- //
- function unpackPrice(uint16 price) internal constant returns (
- Direction direction, uint16 mantissa, int8 exponent
- ) {
- uint sidedPriceIndex = uint(price);
- uint priceIndex;
- if (sidedPriceIndex < 1 || sidedPriceIndex > maxSellPrice) {
- direction = Direction.Invalid;
- mantissa = 0;
- exponent = 0;
- return;
- } else if (sidedPriceIndex <= minBuyPrice) {
- direction = Direction.Buy;
- priceIndex = minBuyPrice - sidedPriceIndex;
- } else {
- direction = Direction.Sell;
- priceIndex = sidedPriceIndex - minSellPrice;
- }
- uint zeroBasedMantissa = priceIndex % 900;
- uint zeroBasedExponent = priceIndex / 900;
- mantissa = uint16(zeroBasedMantissa + 100);
- exponent = int8(zeroBasedExponent) + minPriceExponent;
- return;
- }
-
- // Internal Price Calculation - is a packed price on the buy side?
- //
- // Throws an error if price is invalid.
- //
- function isBuyPrice(uint16 price) internal constant returns (bool isBuy) {
- // yes, this looks odd, but max here is highest _unpacked_ price
- return price >= maxBuyPrice && price <= minBuyPrice;
- }
-
- // Internal Price Calculation - turn a packed buy price into a packed sell price.
- //
- // Invalid price remains invalid.
- //
- function computeOppositePrice(uint16 price) internal constant returns (uint16 opposite) {
- if (price < maxBuyPrice || price > maxSellPrice) {
- return uint16(invalidPrice);
- } else if (price <= minBuyPrice) {
- return uint16(maxSellPrice - (price - maxBuyPrice));
- } else {
- return uint16(maxBuyPrice + (maxSellPrice - price));
- }
- }
-
- // Internal Price Calculation - compute amount in counter currency that would
- // be obtained by selling baseAmount at the given unpacked price (if no fees).
- //
- // Notes:
- // - Does not validate price - caller must ensure valid.
- // - Could overflow producing very unexpected results if baseAmount very
- // large - caller must check this.
- // - This rounds the amount towards zero.
- // - May truncate to zero if baseAmount very small - potentially allowing
- // zero-cost buys or pointless sales - caller must check this.
- //
- function computeCntrAmountUsingUnpacked(
- uint baseAmount, uint16 mantissa, int8 exponent
- ) internal constant returns (uint cntrAmount) {
- if (exponent < 0) {
- return baseAmount * uint(mantissa) / 1000 / 10 ** uint(-exponent);
- } else {
- return baseAmount * uint(mantissa) / 1000 * 10 ** uint(exponent);
- }
- }
-
- // Internal Price Calculation - compute amount in counter currency that would
- // be obtained by selling baseAmount at the given packed price (if no fees).
- //
- // Notes:
- // - Does not validate price - caller must ensure valid.
- // - Direction of the packed price is ignored.
- // - Could overflow producing very unexpected results if baseAmount very
- // large - caller must check this.
- // - This rounds the amount towards zero (regardless of Buy or Sell).
- // - May truncate to zero if baseAmount very small - potentially allowing
- // zero-cost buys or pointless sales - caller must check this.
- //
- function computeCntrAmountUsingPacked(
- uint baseAmount, uint16 price
- ) internal constant returns (uint) {
- var (, mantissa, exponent) = unpackPrice(price);
- return computeCntrAmountUsingUnpacked(baseAmount, mantissa, exponent);
- }
-
- // Public Order Placement - create order and try to match it and/or add it to the book.
- //
- function createOrder(
- uint128 orderId, uint16 price, uint sizeBase, Terms terms, uint maxMatches
- ) public {
- address client = msg.sender;
- require(orderId != 0 && orderForOrderId[orderId].client == 0);
- ClientOrderEvent(client, ClientOrderEventType.Create, orderId, maxMatches);
- orderForOrderId[orderId] =
- Order(client, price, sizeBase, terms, Status.Unknown, ReasonCode.None, 0, 0, 0, 0);
- uint128 previousMostRecentOrderIdForClient = mostRecentOrderIdForClient[client];
- mostRecentOrderIdForClient[client] = orderId;
- clientPreviousOrderIdBeforeOrderId[orderId] = previousMostRecentOrderIdForClient;
- Order storage order = orderForOrderId[orderId];
- var (direction, mantissa, exponent) = unpackPrice(price);
- if (direction == Direction.Invalid) {
- order.status = Status.Rejected;
- order.reasonCode = ReasonCode.InvalidPrice;
- return;
- }
- if (sizeBase < baseMinInitialSize || sizeBase > baseMaxSize) {
- order.status = Status.Rejected;
- order.reasonCode = ReasonCode.InvalidSize;
- return;
- }
- uint sizeCntr = computeCntrAmountUsingUnpacked(sizeBase, mantissa, exponent);
- if (sizeCntr < cntrMinInitialSize || sizeCntr > cntrMaxSize) {
- order.status = Status.Rejected;
- order.reasonCode = ReasonCode.InvalidSize;
- return;
- }
- if (terms == Terms.MakerOnly && maxMatches != 0) {
- order.status = Status.Rejected;
- order.reasonCode = ReasonCode.InvalidTerms;
- return;
- }
- if (!debitFunds(client, direction, sizeBase, sizeCntr)) {
- order.status = Status.Rejected;
- order.reasonCode = ReasonCode.InsufficientFunds;
- return;
- }
- processOrder(orderId, maxMatches);
- }
-
- // Public Order Placement - cancel order
- //
- function cancelOrder(uint128 orderId) public {
- address client = msg.sender;
- Order storage order = orderForOrderId[orderId];
- require(order.client == client);
- Status status = order.status;
- if (status != Status.Open && status != Status.NeedsGas) {
- return;
- }
- ClientOrderEvent(client, ClientOrderEventType.Cancel, orderId, 0);
- if (status == Status.Open) {
- removeOpenOrderFromBook(orderId);
- MarketOrderEvent(block.timestamp, orderId, MarketOrderEventType.Remove, order.price,
- order.sizeBase - order.executedBase, 0);
- }
- refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.ClientCancel);
- }
-
- // Public Order Placement - continue placing an order in 'NeedsGas' state
- //
- function continueOrder(uint128 orderId, uint maxMatches) public {
- address client = msg.sender;
- Order storage order = orderForOrderId[orderId];
- require(order.client == client);
- if (order.status != Status.NeedsGas) {
- return;
- }
- ClientOrderEvent(client, ClientOrderEventType.Continue, orderId, maxMatches);
- order.status = Status.Unknown;
- processOrder(orderId, maxMatches);
- }
-
- // Internal Order Placement - remove a still-open order from the book.
- //
- // Caller's job to update/refund the order + raise event, this just
- // updates the order chain and bitmask.
- //
- // Too expensive to do on each resting order match - we only do this for an
- // order being cancelled. See matchWithOccupiedPrice for similar logic.
- //
- function removeOpenOrderFromBook(uint128 orderId) internal {
- Order storage order = orderForOrderId[orderId];
- uint16 price = order.price;
- OrderChain storage orderChain = orderChainForOccupiedPrice[price];
- OrderChainNode storage orderChainNode = orderChainNodeForOpenOrderId[orderId];
- uint128 nextOrderId = orderChainNode.nextOrderId;
- uint128 prevOrderId = orderChainNode.prevOrderId;
- if (nextOrderId != 0) {
- OrderChainNode storage nextOrderChainNode = orderChainNodeForOpenOrderId[nextOrderId];
- nextOrderChainNode.prevOrderId = prevOrderId;
- } else {
- orderChain.lastOrderId = prevOrderId;
- }
- if (prevOrderId != 0) {
- OrderChainNode storage prevOrderChainNode = orderChainNodeForOpenOrderId[prevOrderId];
- prevOrderChainNode.nextOrderId = nextOrderId;
- } else {
- orderChain.firstOrderId = nextOrderId;
- }
- if (nextOrderId == 0 && prevOrderId == 0) {
- uint bmi = price / 256; // index into array of bitmaps
- uint bti = price % 256; // bit position within bitmap
- // we know was previously occupied so XOR clears
- occupiedPriceBitmaps[bmi] ^= 2 ** bti;
- }
- }
-
- // Internal Order Placement - credit funds received when taking liquidity from book
- //
- function creditExecutedFundsLessFees(uint128 orderId, uint originalExecutedBase, uint originalExecutedCntr) internal {
- Order storage order = orderForOrderId[orderId];
- uint liquidityTakenBase = order.executedBase - originalExecutedBase;
- uint liquidityTakenCntr = order.executedCntr - originalExecutedCntr;
- // Normally we deduct the fee from the currency bought (base for buy, cntr for sell),
- // however we also accept reward tokens from the reward balance if it covers the fee,
- // with the reward amount converted from the ETH amount (the counter currency here)
- // at a fixed exchange rate.
- // Overflow safe since we ensure order size < 10^30 in both currencies (see baseMaxSize).
- // Can truncate to zero, which is fine.
- uint feesRwrd = liquidityTakenCntr / feeDivisor * ethRwrdRate;
- uint feesBaseOrCntr;
- address client = order.client;
- uint availRwrd = balanceRwrdForClient[client];
- if (feesRwrd <= availRwrd) {
- balanceRwrdForClient[client] = availRwrd - feesRwrd;
- balanceRwrdForClient[feeCollector] = feesRwrd;
- // Need += rather than = because could have paid some fees earlier in NeedsGas situation.
- // Overflow safe since we ensure order size < 10^30 in both currencies (see baseMaxSize).
- // Can truncate to zero, which is fine.
- order.feesRwrd += uint128(feesRwrd);
- if (isBuyPrice(order.price)) {
- balanceBaseForClient[client] += liquidityTakenBase;
- } else {
- balanceCntrForClient[client] += liquidityTakenCntr;
- }
- } else if (isBuyPrice(order.price)) {
- // See comments in branch above re: use of += and overflow safety.
- feesBaseOrCntr = liquidityTakenBase / feeDivisor;
- balanceBaseForClient[order.client] += (liquidityTakenBase - feesBaseOrCntr);
- order.feesBaseOrCntr += uint128(feesBaseOrCntr);
- balanceBaseForClient[feeCollector] += feesBaseOrCntr;
- } else {
- // See comments in branch above re: use of += and overflow safety.
- feesBaseOrCntr = liquidityTakenCntr / feeDivisor;
- balanceCntrForClient[order.client] += (liquidityTakenCntr - feesBaseOrCntr);
- order.feesBaseOrCntr += uint128(feesBaseOrCntr);
- balanceCntrForClient[feeCollector] += feesBaseOrCntr;
- }
- }
-
- // Internal Order Placement - process a created and sanity checked order.
- //
- // Used both for new orders and for gas topup.
- //
- function processOrder(uint128 orderId, uint maxMatches) internal {
- Order storage order = orderForOrderId[orderId];
-
- uint ourOriginalExecutedBase = order.executedBase;
- uint ourOriginalExecutedCntr = order.executedCntr;
-
- var (ourDirection,) = unpackPrice(order.price);
- uint theirPriceStart = (ourDirection == Direction.Buy) ? minSellPrice : maxBuyPrice;
- uint theirPriceEnd = computeOppositePrice(order.price);
-
- MatchStopReason matchStopReason =
- matchAgainstBook(orderId, theirPriceStart, theirPriceEnd, maxMatches);
-
- creditExecutedFundsLessFees(orderId, ourOriginalExecutedBase, ourOriginalExecutedCntr);
-
- if (order.terms == Terms.ImmediateOrCancel) {
- if (matchStopReason == MatchStopReason.Satisfied) {
- refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.None);
- return;
- } else if (matchStopReason == MatchStopReason.MaxMatches) {
- refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.TooManyMatches);
- return;
- } else if (matchStopReason == MatchStopReason.BookExhausted) {
- refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.Unmatched);
- return;
- }
- } else if (order.terms == Terms.MakerOnly) {
- if (matchStopReason == MatchStopReason.MaxMatches) {
- refundUnmatchedAndFinish(orderId, Status.Rejected, ReasonCode.WouldTake);
- return;
- } else if (matchStopReason == MatchStopReason.BookExhausted) {
- enterOrder(orderId);
- return;
- }
- } else if (order.terms == Terms.GTCNoGasTopup) {
- if (matchStopReason == MatchStopReason.Satisfied) {
- refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.None);
- return;
- } else if (matchStopReason == MatchStopReason.MaxMatches) {
- refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.TooManyMatches);
- return;
- } else if (matchStopReason == MatchStopReason.BookExhausted) {
- enterOrder(orderId);
- return;
- }
- } else if (order.terms == Terms.GTCWithGasTopup) {
- if (matchStopReason == MatchStopReason.Satisfied) {
- refundUnmatchedAndFinish(orderId, Status.Done, ReasonCode.None);
- return;
- } else if (matchStopReason == MatchStopReason.MaxMatches) {
- order.status = Status.NeedsGas;
- return;
- } else if (matchStopReason == MatchStopReason.BookExhausted) {
- enterOrder(orderId);
- return;
- }
- }
- assert(false); // should not be possible to reach here
- }
-
- // Used internally to indicate why we stopped matching an order against the book.
-
- enum MatchStopReason {
- None,
- MaxMatches,
- Satisfied,
- PriceExhausted,
- BookExhausted
- }
-
- // Internal Order Placement - Match the given order against the book.
- //
- // Resting orders matched will be updated, removed from book and funds credited to their owners.
- //
- // Only updates the executedBase and executedCntr of the given order - caller is responsible
- // for crediting matched funds, charging fees, marking order as done / entering it into the book.
- //
- // matchStopReason returned will be one of MaxMatches, Satisfied or BookExhausted.
- //
- // Calling with maxMatches == 0 is ok - and expected when the order is a maker-only order.
- //
- function matchAgainstBook(
- uint128 orderId, uint theirPriceStart, uint theirPriceEnd, uint maxMatches
- ) internal returns (
- MatchStopReason matchStopReason
- ) {
- Order storage order = orderForOrderId[orderId];
-
- uint bmi = theirPriceStart / 256; // index into array of bitmaps
- uint bti = theirPriceStart % 256; // bit position within bitmap
- uint bmiEnd = theirPriceEnd / 256; // last bitmap to search
- uint btiEnd = theirPriceEnd % 256; // stop at this bit in the last bitmap
-
- uint cbm = occupiedPriceBitmaps[bmi]; // original copy of current bitmap
- uint dbm = cbm; // dirty version of current bitmap where we may have cleared bits
- uint wbm = cbm >> bti; // working copy of current bitmap which we keep shifting
-
- // these loops are pretty ugly, and somewhat unpredicatable in terms of gas,
- // ... but no-one else has come up with a better matching engine yet!
-
- bool removedLastAtPrice;
- matchStopReason = MatchStopReason.None;
-
- while (bmi < bmiEnd) {
- if (wbm == 0 || bti == 256) {
- if (dbm != cbm) {
- occupiedPriceBitmaps[bmi] = dbm;
- }
- bti = 0;
- bmi++;
- cbm = occupiedPriceBitmaps[bmi];
- wbm = cbm;
- dbm = cbm;
- } else {
- if ((wbm & 1) != 0) {
- // careful - copy-and-pasted in loop below ...
- (removedLastAtPrice, maxMatches, matchStopReason) =
- matchWithOccupiedPrice(order, uint16(bmi * 256 + bti), maxMatches);
- if (removedLastAtPrice) {
- dbm ^= 2 ** bti;
- }
- if (matchStopReason == MatchStopReason.PriceExhausted) {
- matchStopReason = MatchStopReason.None;
- } else if (matchStopReason != MatchStopReason.None) {
- // we might still have changes in dbm to write back - see later
- break;
- }
- }
- bti += 1;
- wbm /= 2;
- }
- }
- if (matchStopReason == MatchStopReason.None) {
- // we've reached the last bitmap we need to search,
- // we'll stop at btiEnd not 256 this time.
- while (bti <= btiEnd && wbm != 0) {
- if ((wbm & 1) != 0) {
- // careful - copy-and-pasted in loop above ...
- (removedLastAtPrice, maxMatches, matchStopReason) =
- matchWithOccupiedPrice(order, uint16(bmi * 256 + bti), maxMatches);
- if (removedLastAtPrice) {
- dbm ^= 2 ** bti;
- }
- if (matchStopReason == MatchStopReason.PriceExhausted) {
- matchStopReason = MatchStopReason.None;
- } else if (matchStopReason != MatchStopReason.None) {
- break;
- }
- }
- bti += 1;
- wbm /= 2;
- }
- }
- // Careful - if we exited the first loop early, or we went into the second loop,
- // (luckily can't both happen) then we haven't flushed the dirty bitmap back to
- // storage - do that now if we need to.
- if (dbm != cbm) {
- occupiedPriceBitmaps[bmi] = dbm;
- }
- if (matchStopReason == MatchStopReason.None) {
- matchStopReason = MatchStopReason.BookExhausted;
- }
- }
-
- // Internal Order Placement.
- //
- // Match our order against up to maxMatches resting orders at the given price (which
- // is known by the caller to have at least one resting order).
- //
- // The matches (partial or complete) of the resting orders are recorded, and their
- // funds are credited.
- //
- // The order chain for the resting orders is updated, but the occupied price bitmap is NOT -
- // the caller must clear the relevant bit if removedLastAtPrice = true is returned.
- //
- // Only updates the executedBase and executedCntr of our order - caller is responsible
- // for e.g. crediting our matched funds, updating status.
- //
- // Calling with maxMatches == 0 is ok - and expected when the order is a maker-only order.
- //
- // Returns:
- // removedLastAtPrice:
- // true iff there are no longer any resting orders at this price - caller will need
- // to update the occupied price bitmap.
- //
- // matchesLeft:
- // maxMatches passed in minus the number of matches made by this call
- //
- // matchStopReason:
- // If our order is completely matched, matchStopReason will be Satisfied.
- // If our order is not completely matched, matchStopReason will be either:
- // MaxMatches (we are not allowed to match any more times)
- // or:
- // PriceExhausted (nothing left on the book at this exact price)
- //
- function matchWithOccupiedPrice(
- Order storage ourOrder, uint16 theirPrice, uint maxMatches
- ) internal returns (
- bool removedLastAtPrice, uint matchesLeft, MatchStopReason matchStopReason) {
- matchesLeft = maxMatches;
- uint workingOurExecutedBase = ourOrder.executedBase;
- uint workingOurExecutedCntr = ourOrder.executedCntr;
- uint128 theirOrderId = orderChainForOccupiedPrice[theirPrice].firstOrderId;
- matchStopReason = MatchStopReason.None;
- while (true) {
- if (matchesLeft == 0) {
- matchStopReason = MatchStopReason.MaxMatches;
- break;
- }
- uint matchBase;
- uint matchCntr;
- (theirOrderId, matchBase, matchCntr, matchStopReason) =
- matchWithTheirs((ourOrder.sizeBase - workingOurExecutedBase), theirOrderId, theirPrice);
- workingOurExecutedBase += matchBase;
- workingOurExecutedCntr += matchCntr;
- matchesLeft -= 1;
- if (matchStopReason != MatchStopReason.None) {
- break;
- }
- }
- ourOrder.executedBase = uint128(workingOurExecutedBase);
- ourOrder.executedCntr = uint128(workingOurExecutedCntr);
- if (theirOrderId == 0) {
- orderChainForOccupiedPrice[theirPrice].firstOrderId = 0;
- orderChainForOccupiedPrice[theirPrice].lastOrderId = 0;
- removedLastAtPrice = true;
- } else {
- // NB: in some cases (e.g. maxMatches == 0) this is a no-op.
- orderChainForOccupiedPrice[theirPrice].firstOrderId = theirOrderId;
- orderChainNodeForOpenOrderId[theirOrderId].prevOrderId = 0;
- removedLastAtPrice = false;
- }
- }
-
- // Internal Order Placement.
- //
- // Match up to our remaining amount against a resting order in the book.
- //
- // The match (partial, complete or effectively-complete) of the resting order
- // is recorded, and their funds are credited.
- //
- // Their order is NOT removed from the book by this call - the caller must do that
- // if the nextTheirOrderId returned is not equal to the theirOrderId passed in.
- //
- // Returns:
- //
- // nextTheirOrderId:
- // If we did not completely match their order, will be same as theirOrderId.
- // If we completely matched their order, will be orderId of next order at the
- // same price - or zero if this was the last order and we've now filled it.
- //
- // matchStopReason:
- // If our order is completely matched, matchStopReason will be Satisfied.
- // If our order is not completely matched, matchStopReason will be either
- // PriceExhausted (if nothing left at this exact price) or None (if can continue).
- //
- function matchWithTheirs(
- uint ourRemainingBase, uint128 theirOrderId, uint16 theirPrice) internal returns (
- uint128 nextTheirOrderId, uint matchBase, uint matchCntr, MatchStopReason matchStopReason) {
- Order storage theirOrder = orderForOrderId[theirOrderId];
- uint theirRemainingBase = theirOrder.sizeBase - theirOrder.executedBase;
- if (ourRemainingBase < theirRemainingBase) {
- matchBase = ourRemainingBase;
- } else {
- matchBase = theirRemainingBase;
- }
- matchCntr = computeCntrAmountUsingPacked(matchBase, theirPrice);
- // It may seem a bit odd to stop here if our remaining amount is very small -
- // there could still be resting orders we can match it against. But the gas
- // cost of matching each order is quite high - potentially high enough to
- // wipe out the profit the taker hopes for from trading the tiny amount left.
- if ((ourRemainingBase - matchBase) < baseMinRemainingSize) {
- matchStopReason = MatchStopReason.Satisfied;
- } else {
- matchStopReason = MatchStopReason.None;
- }
- bool theirsDead = recordTheirMatch(theirOrder, theirOrderId, theirPrice, matchBase, matchCntr);
- if (theirsDead) {
- nextTheirOrderId = orderChainNodeForOpenOrderId[theirOrderId].nextOrderId;
- if (matchStopReason == MatchStopReason.None && nextTheirOrderId == 0) {
- matchStopReason = MatchStopReason.PriceExhausted;
- }
- } else {
- nextTheirOrderId = theirOrderId;
- }
- }
-
- // Internal Order Placement.
- //
- // Record match (partial or complete) of resting order, and credit them their funds.
- //
- // If their order is completely matched, the order is marked as done,
- // and "theirsDead" is returned as true.
- //
- // The order is NOT removed from the book by this call - the caller
- // must do that if theirsDead is true.
- //
- // No sanity checks are made - the caller must be sure the order is
- // not already done and has sufficient remaining. (Yes, we'd like to
- // check here too but we cannot afford the gas).
- //
- function recordTheirMatch(
- Order storage theirOrder, uint128 theirOrderId, uint16 theirPrice, uint matchBase, uint matchCntr
- ) internal returns (bool theirsDead) {
- // they are a maker so no fees
- // overflow safe - see comments about baseMaxSize
- // executedBase cannot go > sizeBase due to logic in matchWithTheirs
- theirOrder.executedBase += uint128(matchBase);
- theirOrder.executedCntr += uint128(matchCntr);
- if (isBuyPrice(theirPrice)) {
- // they have bought base (using the counter they already paid when creating the order)
- balanceBaseForClient[theirOrder.client] += matchBase;
- } else {
- // they have bought counter (using the base they already paid when creating the order)
- balanceCntrForClient[theirOrder.client] += matchCntr;
- }
- uint stillRemainingBase = theirOrder.sizeBase - theirOrder.executedBase;
- // avoid leaving tiny amounts in the book - refund remaining if too small
- if (stillRemainingBase < baseMinRemainingSize) {
- refundUnmatchedAndFinish(theirOrderId, Status.Done, ReasonCode.None);
- // someone building an UI on top needs to know how much was match and how much was refund
- MarketOrderEvent(block.timestamp, theirOrderId, MarketOrderEventType.CompleteFill,
- theirPrice, matchBase + stillRemainingBase, matchBase);
- return true;
- } else {
- MarketOrderEvent(block.timestamp, theirOrderId, MarketOrderEventType.PartialFill,
- theirPrice, matchBase, matchBase);
- return false;
- }
- }
-
- // Internal Order Placement.
- //
- // Refund any unmatched funds in an order (based on executed vs size) and move to a final state.
- //
- // The order is NOT removed from the book by this call and no event is raised.
- //
- // No sanity checks are made - the caller must be sure the order has not already been refunded.
- //
- function refundUnmatchedAndFinish(uint128 orderId, Status status, ReasonCode reasonCode) internal {
- Order storage order = orderForOrderId[orderId];
- uint16 price = order.price;
- if (isBuyPrice(price)) {
- uint sizeCntr = computeCntrAmountUsingPacked(order.sizeBase, price);
- balanceCntrForClient[order.client] += sizeCntr - order.executedCntr;
- } else {
- balanceBaseForClient[order.client] += order.sizeBase - order.executedBase;
- }
- order.status = status;
- order.reasonCode = reasonCode;
- }
-
- // Internal Order Placement.
- //
- // Enter a not completely matched order into the book, marking the order as open.
- //
- // This updates the occupied price bitmap and chain.
- //
- // No sanity checks are made - the caller must be sure the order
- // has some unmatched amount and has been paid for!
- //
- function enterOrder(uint128 orderId) internal {
- Order storage order = orderForOrderId[orderId];
- uint16 price = order.price;
- OrderChain storage orderChain = orderChainForOccupiedPrice[price];
- OrderChainNode storage orderChainNode = orderChainNodeForOpenOrderId[orderId];
- if (orderChain.firstOrderId == 0) {
- orderChain.firstOrderId = orderId;
- orderChain.lastOrderId = orderId;
- orderChainNode.nextOrderId = 0;
- orderChainNode.prevOrderId = 0;
- uint bitmapIndex = price / 256;
- uint bitIndex = price % 256;
- occupiedPriceBitmaps[bitmapIndex] |= (2 ** bitIndex);
- } else {
- uint128 existingLastOrderId = orderChain.lastOrderId;
- OrderChainNode storage existingLastOrderChainNode = orderChainNodeForOpenOrderId[existingLastOrderId];
- orderChainNode.nextOrderId = 0;
- orderChainNode.prevOrderId = existingLastOrderId;
- existingLastOrderChainNode.nextOrderId = orderId;
- orderChain.lastOrderId = orderId;
- }
- MarketOrderEvent(block.timestamp, orderId, MarketOrderEventType.Add,
- price, order.sizeBase - order.executedBase, 0);
- order.status = Status.Open;
- }
-
- // Internal Order Placement.
- //
- // Charge the client for the cost of placing an order in the given direction.
- //
- // Return true if successful, false otherwise.
- //
- function debitFunds(
- address client, Direction direction, uint sizeBase, uint sizeCntr
- ) internal returns (bool success) {
- if (direction == Direction.Buy) {
- uint availableCntr = balanceCntrForClient[client];
- if (availableCntr < sizeCntr) {
- return false;
- }
- balanceCntrForClient[client] = availableCntr - sizeCntr;
- return true;
- } else if (direction == Direction.Sell) {
- uint availableBase = balanceBaseForClient[client];
- if (availableBase < sizeBase) {
- return false;
- }
- balanceBaseForClient[client] = availableBase - sizeBase;
- return true;
- } else {
- return false;
- }
- }
-
- // Public Book View
- //
- // Intended for public book depth enumeration from web3 (or similar).
- //
- // Not suitable for use from a smart contract transaction - gas usage
- // could be very high if we have many orders at the same price.
- //
- // Start at the given inclusive price (and side) and walk down the book
- // (getting less aggressive) until we find some open orders or reach the
- // least aggressive price.
- //
- // Returns the price where we found the order(s), the depth at that price
- // (zero if none found), order count there, and the current blockNumber.
- //
- // (The blockNumber is handy if you're taking a snapshot which you intend
- // to keep up-to-date with the market order events).
- //
- // To walk the book, the caller should start by calling walkBook with the
- // most aggressive buy price (Buy @ 999000).
- // If the price returned is the least aggressive buy price (Buy @ 0.000001),
- // the side is complete.
- // Otherwise, call walkBook again with the (packed) price returned + 1.
- // Then repeat for the sell side, starting with Sell @ 0.000001 and stopping
- // when Sell @ 999000 is returned.
- //
- function walkBook(uint16 fromPrice) public constant returns (
- uint16 price, uint depthBase, uint orderCount, uint blockNumber
- ) {
- uint priceStart = fromPrice;
- uint priceEnd = (isBuyPrice(fromPrice)) ? minBuyPrice : maxSellPrice;
-
- // See comments in matchAgainstBook re: how these crazy loops work.
-
- uint bmi = priceStart / 256;
- uint bti = priceStart % 256;
- uint bmiEnd = priceEnd / 256;
- uint btiEnd = priceEnd % 256;
-
- uint wbm = occupiedPriceBitmaps[bmi] >> bti;
-
- while (bmi < bmiEnd) {
- if (wbm == 0 || bti == 256) {
- bti = 0;
- bmi++;
- wbm = occupiedPriceBitmaps[bmi];
- } else {
- if ((wbm & 1) != 0) {
- // careful - copy-pasted in below loop
- price = uint16(bmi * 256 + bti);
- (depthBase, orderCount) = sumDepth(orderChainForOccupiedPrice[price].firstOrderId);
- return (price, depthBase, orderCount, block.number);
- }
- bti += 1;
- wbm /= 2;
- }
- }
- // we've reached the last bitmap we need to search, stop at btiEnd not 256 this time.
- while (bti <= btiEnd && wbm != 0) {
- if ((wbm & 1) != 0) {
- // careful - copy-pasted in above loop
- price = uint16(bmi * 256 + bti);
- (depthBase, orderCount) = sumDepth(orderChainForOccupiedPrice[price].firstOrderId);
- return (price, depthBase, orderCount, block.number);
- }
- bti += 1;
- wbm /= 2;
- }
- return (uint16(priceEnd), 0, 0, block.number);
- }
-
- // Internal Book View.
- //
- // See walkBook - adds up open depth at a price starting from an
- // order which is assumed to be open. Careful - unlimited gas use.
- //
- function sumDepth(uint128 orderId) internal constant returns (uint depth, uint orderCount) {
- while (true) {
- Order storage order = orderForOrderId[orderId];
- depth += order.sizeBase - order.executedBase;
- orderCount++;
- orderId = orderChainNodeForOpenOrderId[orderId].nextOrderId;
- if (orderId == 0) {
- return (depth, orderCount);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/example/errors/Contract2244.sol b/example/errors/Contract2244.sol
deleted file mode 100644
index 75483b9..0000000
--- a/example/errors/Contract2244.sol
+++ /dev/null
@@ -1,807 +0,0 @@
-pragma solidity ^0.4.15;
-
-/**
- * @title MultiSigStub
- * @author Ricardo Guilherme Schmidt (Status Research & Development GmbH)
- * @dev Contract that delegates calls to a library to build a full MultiSigWallet that is cheap to create.
- */
-contract MultiSigStub {
-
- address[] public owners;
- address[] public tokens;
- mapping (uint => Transaction) public transactions;
- mapping (uint => mapping (address => bool)) public confirmations;
- uint public transactionCount;
-
- struct Transaction {
- address destination;
- uint value;
- bytes data;
- bool executed;
- }
-
- function MultiSigStub(address[] _owners, uint256 _required) {
- //bytes4 sig = bytes4(sha3("constructor(address[],uint256)"));
- bytes4 sig = 0x36756a23;
- uint argarraysize = (2 + _owners.length);
- uint argsize = (1 + argarraysize) * 32;
- uint size = 4 + argsize;
- bytes32 mData = _malloc(size);
-
- assembly {
- mstore(mData, sig)
- codecopy(add(mData, 0x4), sub(codesize, argsize), argsize)
- }
- _delegatecall(mData, size);
- }
-
- modifier delegated {
- uint size = msg.data.length;
- bytes32 mData = _malloc(size);
-
- assembly {
- calldatacopy(mData, 0x0, size)
- }
-
- bytes32 mResult = _delegatecall(mData, size);
- _;
- assembly {
- return(mResult, 0x20)
- }
- }
-
- function()
- payable
- delegated
- {
-
- }
-
- function submitTransaction(address destination, uint value, bytes data)
- public
- delegated
- returns (uint)
- {
-
- }
-
- function confirmTransaction(uint transactionId)
- public
- delegated
- {
-
- }
-
- function watch(address _tokenAddr)
- public
- delegated
- {
-
- }
-
- function setMyTokenList(address[] _tokenList)
- public
- delegated
- {
-
- }
- /// @dev Returns the confirmation status of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Confirmation status.
- function isConfirmed(uint transactionId)
- public
- constant
- delegated
- returns (bool)
- {
-
- }
-
- /*
- * Web3 call functions
- */
- function tokenBalances(address tokenAddress)
- public
- constant
- delegated
- returns (uint)
- {
-
- }
-
-
- /// @dev Returns number of confirmations of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Number of confirmations.
- function getConfirmationCount(uint transactionId)
- public
- constant
- delegated
- returns (uint)
- {
-
- }
-
- /// @dev Returns total number of transactions after filters are applied.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Total number of transactions after filters are applied.
- function getTransactionCount(bool pending, bool executed)
- public
- constant
- delegated
- returns (uint)
- {
-
- }
-
- /// @dev Returns list of owners.
- /// @return List of owner addresses.
- function getOwners()
- public
- constant
- returns (address[])
- {
- return owners;
- }
-
- /// @dev Returns list of tokens.
- /// @return List of token addresses.
- function getTokenList()
- public
- constant
- returns (address[])
- {
- return tokens;
- }
-
- /// @dev Returns array with owner addresses, which confirmed transaction.
- /// @param transactionId Transaction ID.
- /// @return Returns array of owner addresses.
- function getConfirmations(uint transactionId)
- public
- constant
- returns (address[] _confirmations)
- {
- address[] memory confirmationsTemp = new address[](owners.length);
- uint count = 0;
- uint i;
- for (i = 0; i < owners.length; i++) {
- if (confirmations[transactionId][owners[i]]) {
- confirmationsTemp[count] = owners[i];
- count += 1;
- }
- }
- _confirmations = new address[](count);
- for (i = 0; i < count; i++) {
- _confirmations[i] = confirmationsTemp[i];
- }
- }
-
- /// @dev Returns list of transaction IDs in defined range.
- /// @param from Index start position of transaction array.
- /// @param to Index end position of transaction array.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Returns array of transaction IDs.
- function getTransactionIds(uint from, uint to, bool pending, bool executed)
- public
- constant
- returns (uint[] _transactionIds)
- {
- uint[] memory transactionIdsTemp = new uint[](transactionCount);
- uint count = 0;
- uint i;
- for (i = 0; i < transactionCount; i++) {
- if (pending && !transactions[i].executed || executed && transactions[i].executed) {
- transactionIdsTemp[count] = i;
- count += 1;
- }
- }
- _transactionIds = new uint[](to - from);
- for (i = from; i < to; i++) {
- _transactionIds[i - from] = transactionIdsTemp[i];
- }
- }
-
-
- function _malloc(uint size)
- private
- returns(bytes32 mData)
- {
- assembly {
- mData := mload(0x40)
- mstore(0x40, add(mData, size))
- }
- }
-
- function _delegatecall(bytes32 mData, uint size)
- private
- returns(bytes32 mResult)
- {
- address target = 0xc0FFeEE61948d8993864a73a099c0E38D887d3F4; //Multinetwork
- mResult = _malloc(32);
- bool failed;
-
- assembly {
- failed := iszero(delegatecall(sub(gas, 10000), target, mData, size, mResult, 0x20))
- }
-
- assert(!failed);
- }
-
-}
-
-contract MultiSigFactory {
-
- event Create(address indexed caller, address createdContract);
-
- function create(address[] owners, uint256 required) returns (address wallet){
- wallet = new MultiSigStub(owners, required);
- Create(msg.sender, wallet);
- }
-
-}
-
-///////////////////////////////////////////////////////////////////
-// MultiSigTokenWallet as in 0xc0FFeEE61948d8993864a73a099c0E38D887d3F4
-///////////////////////////////////////////////////////////////////
-
-pragma solidity ^0.4.15;
-
-contract ERC20 {
- uint256 public totalSupply;
- function balanceOf(address who) constant returns (uint256 balance);
- function allowance(address owner, address spender) constant returns (uint256 remaining);
- function transfer(address to, uint256 value) returns (bool ok);
- function transferFrom(address from, address to, uint256 value) returns (bool ok);
- function approve(address spender, uint256 value) returns (bool ok);
- event Transfer(address indexed from, address indexed to, uint256 value);
- event Approval(address indexed owner, address indexed spender, uint256 value);
-}
-
-contract MultiSigTokenWallet {
-
- address[] public owners;
- address[] public tokens;
- mapping (uint => Transaction) public transactions;
- mapping (uint => mapping (address => bool)) public confirmations;
- uint public transactionCount;
-
- mapping (address => uint) public tokenBalances;
- mapping (address => bool) public isOwner;
- mapping (address => address[]) public userList;
- uint public required;
- uint public nonce;
-
- struct Transaction {
- address destination;
- uint value;
- bytes data;
- bool executed;
- }
-
- uint constant public MAX_OWNER_COUNT = 50;
-
- event Confirmation(address indexed _sender, uint indexed _transactionId);
- event Revocation(address indexed _sender, uint indexed _transactionId);
- event Submission(uint indexed _transactionId);
- event Execution(uint indexed _transactionId);
- event ExecutionFailure(uint indexed _transactionId);
- event Deposit(address indexed _sender, uint _value);
- event TokenDeposit(address _token, address indexed _sender, uint _value);
- event OwnerAddition(address indexed _owner);
- event OwnerRemoval(address indexed _owner);
- event RequirementChange(uint _required);
-
- modifier onlyWallet() {
- require (msg.sender == address(this));
- _;
- }
-
- modifier ownerDoesNotExist(address owner) {
- require (!isOwner[owner]);
- _;
- }
-
- modifier ownerExists(address owner) {
- require (isOwner[owner]);
- _;
- }
-
- modifier transactionExists(uint transactionId) {
- require (transactions[transactionId].destination != 0);
- _;
- }
-
- modifier confirmed(uint transactionId, address owner) {
- require (confirmations[transactionId][owner]);
- _;
- }
-
- modifier notConfirmed(uint transactionId, address owner) {
- require(!confirmations[transactionId][owner]);
- _;
- }
-
- modifier notExecuted(uint transactionId) {
- require (!transactions[transactionId].executed);
- _;
- }
-
- modifier notNull(address _address) {
- require (_address != 0);
- _;
- }
-
- modifier validRequirement(uint ownerCount, uint _required) {
- require (ownerCount <= MAX_OWNER_COUNT && _required <= ownerCount && _required != 0 && ownerCount != 0);
- _;
- }
-
- /// @dev Fallback function allows to deposit ether.
- function()
- payable
- {
- if (msg.value > 0)
- Deposit(msg.sender, msg.value);
- }
-
- /**
- * Public functions
- *
- **/
- /// @dev Contract constructor sets initial owners and required number of confirmations.
- /// @param _owners List of initial owners.
- /// @param _required Number of required confirmations.
- function constructor(address[] _owners, uint _required)
- public
- validRequirement(_owners.length, _required)
- {
- require(owners.length == 0 && required == 0);
- for (uint i = 0; i < _owners.length; i++) {
- require(!isOwner[_owners[i]] && _owners[i] != 0);
- isOwner[_owners[i]] = true;
- }
- owners = _owners;
- required = _required;
- }
-
- /**
- * @notice deposit a ERC20 token. The amount of deposit is the allowance set to this contract.
- * @param _token the token contract address
- * @param _data might be used by child implementations
- **/
- function depositToken(address _token, bytes _data)
- public
- {
- address sender = msg.sender;
- uint amount = ERC20(_token).allowance(sender, this);
- deposit(sender, amount, _token, _data);
- }
-
- /**
- * @notice deposit a ERC20 token. The amount of deposit is the allowance set to this contract.
- * @param _token the token contract address
- * @param _data might be used by child implementations
- **/
- function deposit(address _from, uint256 _amount, address _token, bytes _data)
- public
- {
- if (_from == address(this))
- return;
- uint _nonce = nonce;
- bool result = ERC20(_token).transferFrom(_from, this, _amount);
- assert(result);
- //ERC23 not executed _deposited tokenFallback by
- if (nonce == _nonce) {
- _deposited(_from, _amount, _token, _data);
- }
- }
- /**
- * @notice watches for balance in a token contract
- * @param _tokenAddr the token contract address
- **/
- function watch(address _tokenAddr)
- ownerExists(msg.sender)
- {
- uint oldBal = tokenBalances[_tokenAddr];
- uint newBal = ERC20(_tokenAddr).balanceOf(this);
- if (newBal > oldBal) {
- _deposited(0x0, newBal-oldBal, _tokenAddr, new bytes(0));
- }
- }
-
- function setMyTokenList(address[] _tokenList)
- public
- {
- userList[msg.sender] = _tokenList;
- }
-
- function setTokenList(address[] _tokenList)
- onlyWallet
- {
- tokens = _tokenList;
- }
-
- /**
- * @notice ERC23 Token fallback
- * @param _from address incoming token
- * @param _amount incoming amount
- **/
- function tokenFallback(address _from, uint _amount, bytes _data)
- public
- {
- _deposited(_from, _amount, msg.sender, _data);
- }
-
- /**
- * @notice Called MiniMeToken approvesAndCall to this contract, calls deposit.
- * @param _from address incoming token
- * @param _amount incoming amount
- * @param _token the token contract address
- * @param _data (might be used by child classes)
- */
- function receiveApproval(address _from, uint256 _amount, address _token, bytes _data) {
- deposit(_from, _amount, _token, _data);
- }
-
-
- /// @dev Allows to add a new owner. Transaction has to be sent by wallet.
- /// @param owner Address of new owner.
- function addOwner(address owner)
- public
- onlyWallet
- ownerDoesNotExist(owner)
- notNull(owner)
- validRequirement(owners.length + 1, required)
- {
- isOwner[owner] = true;
- owners.push(owner);
- OwnerAddition(owner);
- }
-
- /// @dev Allows to remove an owner. Transaction has to be sent by wallet.
- /// @param owner Address of owner.
- function removeOwner(address owner)
- public
- onlyWallet
- ownerExists(owner)
- {
- isOwner[owner] = false;
- uint _len = owners.length - 1;
- for (uint i = 0; i < _len; i++) {
- if (owners[i] == owner) {
- owners[i] = owners[owners.length - 1];
- break;
- }
- }
- owners.length -= 1;
- if (required > owners.length)
- changeRequirement(owners.length);
- OwnerRemoval(owner);
- }
-
- /// @dev Allows to replace an owner with a new owner. Transaction has to be sent by wallet.
- /// @param owner Address of owner to be replaced.
- /// @param owner Address of new owner.
- function replaceOwner(address owner, address newOwner)
- public
- onlyWallet
- ownerExists(owner)
- ownerDoesNotExist(newOwner)
- {
- for (uint i = 0; i < owners.length; i++) {
- if (owners[i] == owner) {
- owners[i] = newOwner;
- break;
- }
- }
- isOwner[owner] = false;
- isOwner[newOwner] = true;
- OwnerRemoval(owner);
- OwnerAddition(newOwner);
- }
-
- /**
- * @dev gives full ownership of this wallet to `_dest` removing older owners from wallet
- * @param _dest the address of new controller
- **/
- function releaseWallet(address _dest)
- public
- notNull(_dest)
- ownerDoesNotExist(_dest)
- onlyWallet
- {
- address[] memory _owners = owners;
- uint numOwners = _owners.length;
- addOwner(_dest);
- for (uint i = 0; i < numOwners; i++) {
- removeOwner(_owners[i]);
- }
- }
-
- /// @dev Allows to change the number of required confirmations. Transaction has to be sent by wallet.
- /// @param _required Number of required confirmations.
- function changeRequirement(uint _required)
- public
- onlyWallet
- validRequirement(owners.length, _required)
- {
- required = _required;
- RequirementChange(_required);
- }
-
- /// @dev Allows an owner to submit and confirm a transaction.
- /// @param destination Transaction target address.
- /// @param value Transaction ether value.
- /// @param data Transaction data payload.
- /// @return Returns transaction ID.
- function submitTransaction(address destination, uint value, bytes data)
- public
- returns (uint transactionId)
- {
- transactionId = addTransaction(destination, value, data);
- confirmTransaction(transactionId);
- }
-
- /// @dev Allows an owner to confirm a transaction.
- /// @param transactionId Transaction ID.
- function confirmTransaction(uint transactionId)
- public
- ownerExists(msg.sender)
- transactionExists(transactionId)
- notConfirmed(transactionId, msg.sender)
- {
- confirmations[transactionId][msg.sender] = true;
- Confirmation(msg.sender, transactionId);
- executeTransaction(transactionId);
- }
-
- /// @dev Allows an owner to revoke a confirmation for a transaction.
- /// @param transactionId Transaction ID.
- function revokeConfirmation(uint transactionId)
- public
- ownerExists(msg.sender)
- confirmed(transactionId, msg.sender)
- notExecuted(transactionId)
- {
- confirmations[transactionId][msg.sender] = false;
- Revocation(msg.sender, transactionId);
- }
-
- /// @dev Allows anyone to execute a confirmed transaction.
- /// @param transactionId Transaction ID.
- function executeTransaction(uint transactionId)
- public
- notExecuted(transactionId)
- {
- if (isConfirmed(transactionId)) {
- Transaction storage txx = transactions[transactionId];
- txx.executed = true;
- if (txx.destination.call.value(txx.value)(txx.data)) {
- Execution(transactionId);
- } else {
- ExecutionFailure(transactionId);
- txx.executed = false;
- }
- }
- }
-
- /**
- * @dev withdraw all recognized tokens balances and ether to `_dest`
- * @param _dest the address of receiver
- **/
- function withdrawEverything(address _dest)
- public
- notNull(_dest)
- onlyWallet
- {
- withdrawAllTokens(_dest);
- _dest.transfer(this.balance);
- }
-
- /**
- * @dev withdraw all recognized tokens balances to `_dest`
- * @param _dest the address of receiver
- **/
- function withdrawAllTokens(address _dest)
- public
- notNull(_dest)
- onlyWallet
- {
- address[] memory _tokenList;
- if (userList[_dest].length > 0) {
- _tokenList = userList[_dest];
- } else {
- _tokenList = tokens;
- }
- uint len = _tokenList.length;
- for (uint i = 0;i < len; i++) {
- address _tokenAddr = _tokenList[i];
- uint _amount = tokenBalances[_tokenAddr];
- if (_amount > 0) {
- delete tokenBalances[_tokenAddr];
- ERC20(_tokenAddr).transfer(_dest, _amount);
- }
- }
- }
-
- /**
- * @dev withdraw `_tokenAddr` `_amount` to `_dest`
- * @param _tokenAddr the address of the token
- * @param _dest the address of receiver
- * @param _amount the number of tokens to send
- **/
- function withdrawToken(address _tokenAddr, address _dest, uint _amount)
- public
- notNull(_dest)
- onlyWallet
- {
- require(_amount > 0);
- uint _balance = tokenBalances[_tokenAddr];
- require(_amount <= _balance);
- tokenBalances[_tokenAddr] = _balance - _amount;
- bool result = ERC20(_tokenAddr).transfer(_dest, _amount);
- assert(result);
- }
-
- /// @dev Returns the confirmation status of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Confirmation status.
- function isConfirmed(uint transactionId)
- public
- constant
- returns (bool)
- {
- uint count = 0;
- for (uint i = 0; i < owners.length; i++) {
- if (confirmations[transactionId][owners[i]])
- count += 1;
- if (count == required)
- return true;
- }
- }
-
- /*
- * Internal functions
- */
- /// @dev Adds a new transaction to the transaction mapping, if transaction does not exist yet.
- /// @param destination Transaction target address.
- /// @param value Transaction ether value.
- /// @param data Transaction data payload.
- /// @return Returns transaction ID.
- function addTransaction(address destination, uint value, bytes data)
- internal
- notNull(destination)
- returns (uint transactionId)
- {
- transactionId = transactionCount;
- transactions[transactionId] = Transaction({
- destination: destination,
- value: value,
- data: data,
- executed: false
- });
- transactionCount += 1;
- Submission(transactionId);
- }
-
- /**
- * @dev register the deposit
- **/
- function _deposited(address _from, uint _amount, address _tokenAddr, bytes)
- internal
- {
- TokenDeposit(_tokenAddr,_from,_amount);
- nonce++;
- if (tokenBalances[_tokenAddr] == 0) {
- tokens.push(_tokenAddr);
- tokenBalances[_tokenAddr] = ERC20(_tokenAddr).balanceOf(this);
- } else {
- tokenBalances[_tokenAddr] += _amount;
- }
- }
-
- /*
- * Web3 call functions
- */
- /// @dev Returns number of confirmations of a transaction.
- /// @param transactionId Transaction ID.
- /// @return Number of confirmations.
- function getConfirmationCount(uint transactionId)
- public
- constant
- returns (uint count)
- {
- for (uint i = 0; i < owners.length; i++) {
- if (confirmations[transactionId][owners[i]])
- count += 1;
- }
- }
-
- /// @dev Returns total number of transactions after filters are applied.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Total number of transactions after filters are applied.
- function getTransactionCount(bool pending, bool executed)
- public
- constant
- returns (uint count)
- {
- for (uint i = 0; i < transactionCount; i++) {
- if (pending && !transactions[i].executed || executed && transactions[i].executed)
- count += 1;
- }
- }
-
- /// @dev Returns list of owners.
- /// @return List of owner addresses.
- function getOwners()
- public
- constant
- returns (address[])
- {
- return owners;
- }
-
- /// @dev Returns list of tokens.
- /// @return List of token addresses.
- function getTokenList()
- public
- constant
- returns (address[])
- {
- return tokens;
- }
-
- /// @dev Returns array with owner addresses, which confirmed transaction.
- /// @param transactionId Transaction ID.
- /// @return Returns array of owner addresses.
- function getConfirmations(uint transactionId)
- public
- constant
- returns (address[] _confirmations)
- {
- address[] memory confirmationsTemp = new address[](owners.length);
- uint count = 0;
- uint i;
- for (i = 0; i < owners.length; i++) {
- if (confirmations[transactionId][owners[i]]) {
- confirmationsTemp[count] = owners[i];
- count += 1;
- }
- }
- _confirmations = new address[](count);
- for (i = 0; i < count; i++) {
- _confirmations[i] = confirmationsTemp[i];
- }
- }
-
- /// @dev Returns list of transaction IDs in defined range.
- /// @param from Index start position of transaction array.
- /// @param to Index end position of transaction array.
- /// @param pending Include pending transactions.
- /// @param executed Include executed transactions.
- /// @return Returns array of transaction IDs.
- function getTransactionIds(uint from, uint to, bool pending, bool executed)
- public
- constant
- returns (uint[] _transactionIds)
- {
- uint[] memory transactionIdsTemp = new uint[](transactionCount);
- uint count = 0;
- uint i;
- for (i = 0; i < transactionCount; i++) {
- if (pending && !transactions[i].executed || executed && transactions[i].executed) {
- transactionIdsTemp[count] = i;
- count += 1;
- }
- }
- _transactionIds = new uint[](to - from);
- for (i = from; i < to; i++) {
- _transactionIds[i - from] = transactionIdsTemp[i];
- }
- }
-
-}
\ No newline at end of file
diff --git a/example/errors/Contract365.sol b/example/errors/Contract365.sol
deleted file mode 100644
index 634651b..0000000
--- a/example/errors/Contract365.sol
+++ /dev/null
@@ -1,155 +0,0 @@
-// SPDX-License-Identifier: LGPL-3.0-only
-pragma solidity >=0.7.0 <0.9.0;
-
-/// @title IProxy - Helper interface to access masterCopy of the Proxy on-chain
-/// @author Richard Meissner -
-interface IProxy {
- function masterCopy() external view returns (address);
-}
-
-/// @title GnosisSafeProxy - Generic proxy contract allows to execute all transactions applying the code of a master contract.
-/// @author Stefan George -
-/// @author Richard Meissner -
-contract GnosisSafeProxy {
- // singleton always needs to be first declared variable, to ensure that it is at the same location in the contracts to which calls are delegated.
- // To reduce deployment costs this variable is internal and needs to be retrieved via `getStorageAt`
- address internal singleton;
-
- /// @dev Constructor function sets address of singleton contract.
- /// @param _singleton Singleton address.
- constructor(address _singleton) {
- require(_singleton != address(0), "Invalid singleton address provided");
- singleton = _singleton;
- }
-
- /// @dev Fallback function forwards all transactions and returns all received return data.
- fallback() external payable {
- // solhint-disable-next-line no-inline-assembly
- assembly {
- let _singleton := and(sload(0), 0xffffffffffffffffffffffffffffffffffffffff)
- // 0xa619486e == keccak("masterCopy()"). The value is right padded to 32-bytes with 0s
- if eq(calldataload(0), 0xa619486e00000000000000000000000000000000000000000000000000000000) {
- mstore(0, _singleton)
- return(0, 0x20)
- }
- calldatacopy(0, 0, calldatasize())
- let success := delegatecall(gas(), _singleton, 0, calldatasize(), 0, 0)
- returndatacopy(0, 0, returndatasize())
- if eq(success, 0) {
- revert(0, returndatasize())
- }
- return(0, returndatasize())
- }
- }
-}
-
-/// @title Proxy Factory - Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
-/// @author Stefan George -
-contract GnosisSafeProxyFactory {
- event ProxyCreation(GnosisSafeProxy proxy, address singleton);
-
- /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
- /// @param singleton Address of singleton contract.
- /// @param data Payload for message call sent to new proxy contract.
- function createProxy(address singleton, bytes memory data) public returns (GnosisSafeProxy proxy) {
- proxy = new GnosisSafeProxy(singleton);
- if (data.length > 0)
- // solhint-disable-next-line no-inline-assembly
- assembly {
- if eq(call(gas(), proxy, 0, add(data, 0x20), mload(data), 0, 0), 0) {
- revert(0, 0)
- }
- }
- emit ProxyCreation(proxy, singleton);
- }
-
- /// @dev Allows to retrieve the runtime code of a deployed Proxy. This can be used to check that the expected Proxy was deployed.
- function proxyRuntimeCode() public pure returns (bytes memory) {
- return type(GnosisSafeProxy).runtimeCode;
- }
-
- /// @dev Allows to retrieve the creation code used for the Proxy deployment. With this it is easily possible to calculate predicted address.
- function proxyCreationCode() public pure returns (bytes memory) {
- return type(GnosisSafeProxy).creationCode;
- }
-
- /// @dev Allows to create new proxy contact using CREATE2 but it doesn't run the initializer.
- /// This method is only meant as an utility to be called from other methods
- /// @param _singleton Address of singleton contract.
- /// @param initializer Payload for message call sent to new proxy contract.
- /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
- function deployProxyWithNonce(
- address _singleton,
- bytes memory initializer,
- uint256 saltNonce
- ) internal returns (GnosisSafeProxy proxy) {
- // If the initializer changes the proxy address should change too. Hashing the initializer data is cheaper than just concatinating it
- bytes32 salt = keccak256(abi.encodePacked(keccak256(initializer), saltNonce));
- bytes memory deploymentData = abi.encodePacked(type(GnosisSafeProxy).creationCode, uint256(uint160(_singleton)));
- // solhint-disable-next-line no-inline-assembly
- assembly {
- proxy := create2(0x0, add(0x20, deploymentData), mload(deploymentData), salt)
- }
- require(address(proxy) != address(0), "Create2 call failed");
- }
-
- /// @dev Allows to create new proxy contact and execute a message call to the new proxy within one transaction.
- /// @param _singleton Address of singleton contract.
- /// @param initializer Payload for message call sent to new proxy contract.
- /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
- function createProxyWithNonce(
- address _singleton,
- bytes memory initializer,
- uint256 saltNonce
- ) public returns (GnosisSafeProxy proxy) {
- proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
- if (initializer.length > 0)
- // solhint-disable-next-line no-inline-assembly
- assembly {
- if eq(call(gas(), proxy, 0, add(initializer, 0x20), mload(initializer), 0, 0), 0) {
- revert(0, 0)
- }
- }
- emit ProxyCreation(proxy, _singleton);
- }
-
- /// @dev Allows to create new proxy contact, execute a message call to the new proxy and call a specified callback within one transaction
- /// @param _singleton Address of singleton contract.
- /// @param initializer Payload for message call sent to new proxy contract.
- /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
- /// @param callback Callback that will be invoced after the new proxy contract has been successfully deployed and initialized.
- function createProxyWithCallback(
- address _singleton,
- bytes memory initializer,
- uint256 saltNonce,
- IProxyCreationCallback callback
- ) public returns (GnosisSafeProxy proxy) {
- uint256 saltNonceWithCallback = uint256(keccak256(abi.encodePacked(saltNonce, callback)));
- proxy = createProxyWithNonce(_singleton, initializer, saltNonceWithCallback);
- if (address(callback) != address(0)) callback.proxyCreated(proxy, _singleton, initializer, saltNonce);
- }
-
- /// @dev Allows to get the address for a new proxy contact created via `createProxyWithNonce`
- /// This method is only meant for address calculation purpose when you use an initializer that would revert,
- /// therefore the response is returned with a revert. When calling this method set `from` to the address of the proxy factory.
- /// @param _singleton Address of singleton contract.
- /// @param initializer Payload for message call sent to new proxy contract.
- /// @param saltNonce Nonce that will be used to generate the salt to calculate the address of the new proxy contract.
- function calculateCreateProxyWithNonceAddress(
- address _singleton,
- bytes calldata initializer,
- uint256 saltNonce
- ) external returns (GnosisSafeProxy proxy) {
- proxy = deployProxyWithNonce(_singleton, initializer, saltNonce);
- revert(string(abi.encodePacked(proxy)));
- }
-}
-
-interface IProxyCreationCallback {
- function proxyCreated(
- GnosisSafeProxy proxy,
- address _singleton,
- bytes calldata initializer,
- uint256 saltNonce
- ) external;
-}
\ No newline at end of file
diff --git a/example/errors/Contract42.sol b/example/errors/Contract42.sol
deleted file mode 100644
index 52ed3f7..0000000
--- a/example/errors/Contract42.sol
+++ /dev/null
@@ -1,638 +0,0 @@
-// File: openzeppelin-solidity/contracts/ownership/Ownable.sol
-
-pragma solidity ^0.5.0;
-
-/**
- * @title Ownable
- * @dev The Ownable contract has an owner address, and provides basic authorization control
- * functions, this simplifies the implementation of "user permissions".
- */
-contract Ownable {
- address private _owner;
-
- event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
-
- /**
- * @dev The Ownable constructor sets the original `owner` of the contract to the sender
- * account.
- */
- constructor () internal {
- _owner = msg.sender;
- emit OwnershipTransferred(address(0), _owner);
- }
-
- /**
- * @return the address of the owner.
- */
- function owner() public view returns (address) {
- return _owner;
- }
-
- /**
- * @dev Throws if called by any account other than the owner.
- */
- modifier onlyOwner() {
- require(isOwner());
- _;
- }
-
- /**
- * @return true if `msg.sender` is the owner of the contract.
- */
- function isOwner() public view returns (bool) {
- return msg.sender == _owner;
- }
-
- /**
- * @dev Allows the current owner to relinquish control of the contract.
- * @notice Renouncing to ownership will leave the contract without an owner.
- * It will not be possible to call the functions with the `onlyOwner`
- * modifier anymore.
- */
- function renounceOwnership() public onlyOwner {
- emit OwnershipTransferred(_owner, address(0));
- _owner = address(0);
- }
-
- /**
- * @dev Allows the current owner to transfer control of the contract to a newOwner.
- * @param newOwner The address to transfer ownership to.
- */
- function transferOwnership(address newOwner) public onlyOwner {
- _transferOwnership(newOwner);
- }
-
- /**
- * @dev Transfers control of the contract to a newOwner.
- * @param newOwner The address to transfer ownership to.
- */
- function _transferOwnership(address newOwner) internal {
- require(newOwner != address(0));
- emit OwnershipTransferred(_owner, newOwner);
- _owner = newOwner;
- }
-}
-
-// File: openzeppelin-solidity/contracts/math/SafeMath.sol
-
-pragma solidity ^0.5.0;
-
-/**
- * @title SafeMath
- * @dev Unsigned math operations with safety checks that revert on error
- */
-library SafeMath {
- /**
- * @dev Multiplies two unsigned integers, reverts on overflow.
- */
- function mul(uint256 a, uint256 b) internal pure returns (uint256) {
- // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
- // benefit is lost if 'b' is also tested.
- // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
- if (a == 0) {
- return 0;
- }
-
- uint256 c = a * b;
- require(c / a == b);
-
- return c;
- }
-
- /**
- * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
- */
- function div(uint256 a, uint256 b) internal pure returns (uint256) {
- // Solidity only automatically asserts when dividing by 0
- require(b > 0);
- uint256 c = a / b;
- // assert(a == b * c + a % b); // There is no case in which this doesn't hold
-
- return c;
- }
-
- /**
- * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
- */
- function sub(uint256 a, uint256 b) internal pure returns (uint256) {
- require(b <= a);
- uint256 c = a - b;
-
- return c;
- }
-
- /**
- * @dev Adds two unsigned integers, reverts on overflow.
- */
- function add(uint256 a, uint256 b) internal pure returns (uint256) {
- uint256 c = a + b;
- require(c >= a);
-
- return c;
- }
-
- /**
- * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
- * reverts when dividing by zero.
- */
- function mod(uint256 a, uint256 b) internal pure returns (uint256) {
- require(b != 0);
- return a % b;
- }
-}
-
-// File: openzeppelin-solidity/contracts/access/Roles.sol
-
-pragma solidity ^0.5.0;
-
-/**
- * @title Roles
- * @dev Library for managing addresses assigned to a Role.
- */
-library Roles {
- struct Role {
- mapping (address => bool) bearer;
- }
-
- /**
- * @dev give an account access to this role
- */
- function add(Role storage role, address account) internal {
- require(account != address(0));
- require(!has(role, account));
-
- role.bearer[account] = true;
- }
-
- /**
- * @dev remove an account's access to this role
- */
- function remove(Role storage role, address account) internal {
- require(account != address(0));
- require(has(role, account));
-
- role.bearer[account] = false;
- }
-
- /**
- * @dev check if an account has this role
- * @return bool
- */
- function has(Role storage role, address account) internal view returns (bool) {
- require(account != address(0));
- return role.bearer[account];
- }
-}
-
-// File: openzeppelin-solidity/contracts/access/roles/PauserRole.sol
-
-pragma solidity ^0.5.0;
-
-
-contract PauserRole {
- using Roles for Roles.Role;
-
- event PauserAdded(address indexed account);
- event PauserRemoved(address indexed account);
-
- Roles.Role private _pausers;
-
- constructor () internal {
- _addPauser(msg.sender);
- }
-
- modifier onlyPauser() {
- require(isPauser(msg.sender));
- _;
- }
-
- function isPauser(address account) public view returns (bool) {
- return _pausers.has(account);
- }
-
- function addPauser(address account) public onlyPauser {
- _addPauser(account);
- }
-
- function renouncePauser() public {
- _removePauser(msg.sender);
- }
-
- function _addPauser(address account) internal {
- _pausers.add(account);
- emit PauserAdded(account);
- }
-
- function _removePauser(address account) internal {
- _pausers.remove(account);
- emit PauserRemoved(account);
- }
-}
-
-// File: openzeppelin-solidity/contracts/lifecycle/Pausable.sol
-
-pragma solidity ^0.5.0;
-
-
-/**
- * @title Pausable
- * @dev Base contract which allows children to implement an emergency stop mechanism.
- */
-contract Pausable is PauserRole {
- event Paused(address account);
- event Unpaused(address account);
-
- bool private _paused;
-
- constructor () internal {
- _paused = false;
- }
-
- /**
- * @return true if the contract is paused, false otherwise.
- */
- function paused() public view returns (bool) {
- return _paused;
- }
-
- /**
- * @dev Modifier to make a function callable only when the contract is not paused.
- */
- modifier whenNotPaused() {
- require(!_paused);
- _;
- }
-
- /**
- * @dev Modifier to make a function callable only when the contract is paused.
- */
- modifier whenPaused() {
- require(_paused);
- _;
- }
-
- /**
- * @dev called by the owner to pause, triggers stopped state
- */
- function pause() public onlyPauser whenNotPaused {
- _paused = true;
- emit Paused(msg.sender);
- }
-
- /**
- * @dev called by the owner to unpause, returns to normal state
- */
- function unpause() public onlyPauser whenPaused {
- _paused = false;
- emit Unpaused(msg.sender);
- }
-}
-
-// File: contracts/libs/Strings.sol
-
-pragma solidity 0.5.0;
-
-library Strings {
-
- // via https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_0.5.sol
- function strConcat(string memory _a, string memory _b, string memory _c, string memory _d, string memory _e) internal pure returns (string memory _concatenatedString) {
- bytes memory _ba = bytes(_a);
- bytes memory _bb = bytes(_b);
- bytes memory _bc = bytes(_c);
- bytes memory _bd = bytes(_d);
- bytes memory _be = bytes(_e);
- string memory abcde = new string(_ba.length + _bb.length + _bc.length + _bd.length + _be.length);
- bytes memory babcde = bytes(abcde);
- uint k = 0;
- uint i = 0;
- for (i = 0; i < _ba.length; i++) {
- babcde[k++] = _ba[i];
- }
- for (i = 0; i < _bb.length; i++) {
- babcde[k++] = _bb[i];
- }
- for (i = 0; i < _bc.length; i++) {
- babcde[k++] = _bc[i];
- }
- for (i = 0; i < _bd.length; i++) {
- babcde[k++] = _bd[i];
- }
- for (i = 0; i < _be.length; i++) {
- babcde[k++] = _be[i];
- }
- return string(babcde);
- }
-
- function strConcat(string memory _a, string memory _b) internal pure returns (string memory) {
- return strConcat(_a, _b, "", "", "");
- }
-
- function strConcat(string memory _a, string memory _b, string memory _c) internal pure returns (string memory) {
- return strConcat(_a, _b, _c, "", "");
- }
-
- function uint2str(uint _i) internal pure returns (string memory _uintAsString) {
- if (_i == 0) {
- return "0";
- }
- uint j = _i;
- uint len;
- while (j != 0) {
- len++;
- j /= 10;
- }
- bytes memory bstr = new bytes(len);
- uint k = len - 1;
- while (_i != 0) {
- bstr[k--] = byte(uint8(48 + _i % 10));
- _i /= 10;
- }
- return string(bstr);
- }
-}
-
-// File: contracts/INiftyTradingCardCreator.sol
-
-pragma solidity 0.5.0;
-
-interface INiftyTradingCardCreator {
- function mintCard(
- uint256 _cardType,
- uint256 _nationality,
- uint256 _position,
- uint256 _ethnicity,
- uint256 _kit,
- uint256 _colour,
- address _to
- ) external returns (uint256 _tokenId);
-
- function setAttributes(
- uint256 _tokenId,
- uint256 _strength,
- uint256 _speed,
- uint256 _intelligence,
- uint256 _skill
- ) external returns (bool);
-
- function setName(
- uint256 _tokenId,
- uint256 _firstName,
- uint256 _lastName
- ) external returns (bool);
-
- function setAttributesAndName(
- uint256 _tokenId,
- uint256 _strength,
- uint256 _speed,
- uint256 _intelligence,
- uint256 _skill,
- uint256 _firstName,
- uint256 _lastName
- ) external returns (bool);
-}
-
-// File: contracts/generators/INiftyFootballTradingCardGenerator.sol
-
-pragma solidity 0.5.0;
-
-contract INiftyFootballTradingCardGenerator {
- function generateCard(address _sender) external returns (uint256 _nationality, uint256 _position, uint256 _ethnicity, uint256 _kit, uint256 _colour);
-
- function generateAttributes(address _sender, uint256 _base) external returns (uint256 strength, uint256 speed, uint256 intelligence, uint256 skill);
-
- function generateName(address _sender) external returns (uint256 firstName, uint256 lastName);
-}
-
-// File: contracts/FundsSplitter.sol
-
-pragma solidity ^0.5.0;
-
-
-
-contract FundsSplitter is Ownable {
- using SafeMath for uint256;
-
- address payable public platform;
- address payable public partner;
-
- uint256 public partnerRate = 7;
-
- constructor (address payable _platform, address payable _partner) public {
- platform = _platform;
- partner = _partner;
- }
-
- function splitFunds(uint256 _totalPrice) internal {
- if (msg.value > 0) {
- uint256 refund = msg.value.sub(_totalPrice);
-
- // overpaid...
- if (refund > 0) {
- msg.sender.transfer(refund);
- }
-
- // work out the amount to split and send it
- uint256 partnerAmount = _totalPrice.div(100).mul(partnerRate);
- partner.transfer(partnerAmount);
-
- // send remaining amount to partner wallet
- uint256 remaining = _totalPrice.sub(partnerAmount);
- platform.transfer(remaining);
- }
- }
-
- function updatePartnerAddress(address payable _partner) onlyOwner public {
- partner = _partner;
- }
-
- function updatePartnerRate(uint256 _techPartnerRate) onlyOwner public {
- partnerRate = _techPartnerRate;
- }
-
- function updatePlatformAddress(address payable _platform) onlyOwner public {
- platform = _platform;
- }
-
- function withdraw() public onlyOwner returns (bool) {
- platform.transfer(address(this).balance);
- return true;
- }
-}
-
-// File: contracts/NiftyFootballTradingCardEliteBlindPack.sol
-
-pragma solidity 0.5.0;
-
-
-
-
-
-
-
-
-
-contract NiftyFootballTradingCardEliteBlindPack is Ownable, Pausable, FundsSplitter {
- using SafeMath for uint256;
-
- event PriceInWeiChanged(uint256 _old, uint256 _new);
-
- event DefaultCardTypeChanged(uint256 _new);
-
- event AttributesBaseChanged(uint256 _new);
-
- event FutballCardsGeneratorChanged(INiftyFootballTradingCardGenerator _new);
-
- INiftyFootballTradingCardGenerator public generator;
- INiftyTradingCardCreator public creator;
-
- uint256 public totalPurchasesInWei = 0;
- uint256 public cardTypeDefault = 0;
- uint256 public attributesBase = 60; // Standard 60-100
-
- uint256[] public pricePerCard = [
- // single cards
- 16000000000000000, // 1 @ = 0.016 ETH / $2.50
- 16000000000000000, // 2 @ = 0.016 ETH / $2.50
-
- // 1 packs
- 14500000000000000, // 3 @ = 0.0145 ETH / $2.30
- 14500000000000000, // 4 @ = 0.0145 ETH / $2.30
- 14500000000000000, // 5 @ = 0.0145 ETH / $2.30
-
- // 2 packs
- 13500000000000000, // 6 @ = 0.0135 ETH / $2.15
- 13500000000000000, // 7 @ = 0.0135 ETH / $2.15
- 13500000000000000, // 8 @ = 0.0135 ETH / $2.15
-
- // 3 packs or more
- 12500000000000000, // 9 @ = 0.0125 ETH / $2
- 12500000000000000 // 10 @ = 0.0125 ETH / $2
- ];
-
- constructor (
- address payable _wallet,
- address payable _partnerAddress,
- INiftyFootballTradingCardGenerator _generator,
- INiftyTradingCardCreator _creator
- ) public FundsSplitter(_wallet, _partnerAddress) {
- generator = _generator;
- creator = _creator;
- }
-
- function blindPack() whenNotPaused public payable {
- blindPackTo(msg.sender);
- }
-
- function blindPackTo(address _to) whenNotPaused public payable {
- uint256 _totalPrice = totalPrice(1);
- require(
- msg.value >= _totalPrice,
- "Must supply at least the required minimum purchase value"
- );
- require(!isContract(msg.sender), "Unable to buy packs from another contract");
-
- _generateAndAssignCard(_to);
-
- _takePayment(1, _totalPrice);
- }
-
- function buyBatch(uint256 _numberOfCards) whenNotPaused public payable {
- return buyBatchTo(msg.sender, _numberOfCards);
- }
-
- function buyBatchTo(address _to, uint256 _numberOfCards) whenNotPaused public payable {
- uint256 _totalPrice = totalPrice(_numberOfCards);
- require(
- msg.value >= _totalPrice,
- "Must supply at least the required minimum purchase value"
- );
- require(!isContract(msg.sender), "Unable to buy packs from another contract");
-
- for (uint i = 0; i < _numberOfCards; i++) {
- _generateAndAssignCard(_to);
- }
-
- _takePayment(_numberOfCards, _totalPrice);
- }
-
- function _generateAndAssignCard(address _to) internal {
- // Generate card
- (uint256 _nationality, uint256 _position, uint256 _ethnicity, uint256 _kit, uint256 _colour) = generator.generateCard(msg.sender);
-
- // cardType is 0 for genesis (initially)
- uint256 tokenId = creator.mintCard(cardTypeDefault, _nationality, _position, _ethnicity, _kit, _colour, _to);
-
- // Generate attributes
- (uint256 _strength, uint256 _speed, uint256 _intelligence, uint256 _skill) = generator.generateAttributes(msg.sender, attributesBase);
- (uint256 _firstName, uint256 _lastName) = generator.generateName(msg.sender);
-
- creator.setAttributesAndName(tokenId, _strength, _speed, _intelligence, _skill, _firstName, _lastName);
- }
-
- function _takePayment(uint256 _numberOfCards, uint256 _totalPrice) internal {
- // any trapped ether can be withdrawn with withdraw()
- totalPurchasesInWei = totalPurchasesInWei.add(_totalPrice);
- splitFunds(_totalPrice);
- }
-
- function setCardTypeDefault(uint256 _newDefaultCardType) public onlyOwner returns (bool) {
- cardTypeDefault = _newDefaultCardType;
-
- emit DefaultCardTypeChanged(_newDefaultCardType);
-
- return true;
- }
-
- function setAttributesBase(uint256 _newAttributesBase) public onlyOwner returns (bool) {
- attributesBase = _newAttributesBase;
-
- emit AttributesBaseChanged(_newAttributesBase);
-
- return true;
- }
-
- function setFutballCardsGenerator(INiftyFootballTradingCardGenerator _futballCardsGenerator) public onlyOwner returns (bool) {
- generator = _futballCardsGenerator;
-
- emit FutballCardsGeneratorChanged(_futballCardsGenerator);
-
- return true;
- }
-
- function updatePricePerCardAtIndex(uint256 _index, uint256 _priceInWei) public onlyOwner returns (bool) {
- pricePerCard[_index] = _priceInWei;
- return true;
- }
-
- function updatePricePerCard(uint256[] memory _pricePerCard) public onlyOwner returns (bool) {
- pricePerCard = _pricePerCard;
- return true;
- }
-
- function totalPrice(uint256 _numberOfCards) public view returns (uint256) {
- if (_numberOfCards > pricePerCard.length) {
- return pricePerCard[pricePerCard.length - 1].mul(_numberOfCards);
- }
- return pricePerCard[_numberOfCards - 1].mul(_numberOfCards);
- }
-
- /**
- * Returns whether the target address is a contract
- * Based on OpenZeppelin Address library
- * @dev This function will return false if invoked during the constructor of a contract,
- * as the code is not actually created until after the constructor finishes.
- * @param account address of the account to check
- * @return whether the target address is a contract
- */
- function isContract(address account) internal view returns (bool) {
- uint256 size;
- // XXX Currently there is no better way to check if there is a contract in an address
- // than to check the size of the code at that address.
- // See https://ethereum.stackexchange.com/a/14016/36603
- // for more details about how this works.
- // contracts then.
- // solhint-disable-next-line no-inline-assembly
- assembly {size := extcodesize(account)}
- return size > 0;
- }
-}
\ No newline at end of file
diff --git a/example/errors/Contract5189.sol b/example/errors/Contract5189.sol
deleted file mode 100644
index 850d69f..0000000
--- a/example/errors/Contract5189.sol
+++ /dev/null
@@ -1,674 +0,0 @@
-pragma solidity ^0.5.10;
-
-/** @title BitcoinSPV */
-/** @author Summa (https://summa.one) */
-
-import {BytesLib} from "./BytesLib.sol";
-import {SafeMath} from "./SafeMath.sol";
-
-library BTCUtils {
- using BytesLib for bytes;
- using SafeMath for uint256;
-
- // The target at minimum Difficulty. Also the target of the genesis block
- uint256 public constant DIFF1_TARGET = 0xffff0000000000000000000000000000000000000000000000000000;
-
- uint256 public constant RETARGET_PERIOD = 2 * 7 * 24 * 60 * 60; // 2 weeks in seconds
- uint256 public constant RETARGET_PERIOD_BLOCKS = 2016; // 2 weeks in blocks
-
- uint256 public constant ERR_BAD_ARG = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
-
- /* ***** */
- /* UTILS */
- /* ***** */
-
- /// @notice Determines the length of a VarInt in bytes
- /// @dev A VarInt of >1 byte is prefixed with a flag indicating its length
- /// @param _flag The first byte of a VarInt
- /// @return The number of non-flag bytes in the VarInt
- function determineVarIntDataLength(bytes memory _flag) internal pure returns (uint8) {
- if (uint8(_flag[0]) == 0xff) {
- return 8; // one-byte flag, 8 bytes data
- }
- if (uint8(_flag[0]) == 0xfe) {
- return 4; // one-byte flag, 4 bytes data
- }
- if (uint8(_flag[0]) == 0xfd) {
- return 2; // one-byte flag, 2 bytes data
- }
-
- return 0; // flag is data
- }
-
- /// @notice Parse a VarInt into its data length and the number it represents
- /// @dev Useful for Parsing Vins and Vouts. Returns ERR_BAD_ARG if insufficient bytes.
- /// Caller SHOULD explicitly handle this case (or bubble it up)
- /// @param _b A byte-string starting with a VarInt
- /// @return number of bytes in the encoding (not counting the tag), the encoded int
- function parseVarInt(bytes memory _b) internal pure returns (uint256, uint256) {
- uint8 _dataLen = determineVarIntDataLength(_b);
-
- if (_dataLen == 0) {
- return (0, uint8(_b[0]));
- }
- if (_b.length < 1 + _dataLen) {
- return (ERR_BAD_ARG, 0);
- }
- uint256 _number = bytesToUint(reverseEndianness(_b.slice(1, _dataLen)));
- return (_dataLen, _number);
- }
-
- /// @notice Changes the endianness of a byte array
- /// @dev Returns a new, backwards, bytes
- /// @param _b The bytes to reverse
- /// @return The reversed bytes
- function reverseEndianness(bytes memory _b) internal pure returns (bytes memory) {
- bytes memory _newValue = new bytes(_b.length);
-
- for (uint i = 0; i < _b.length; i++) {
- _newValue[_b.length - i - 1] = _b[i];
- }
-
- return _newValue;
- }
-
- /// @notice Changes the endianness of a uint256
- /// @dev https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel
- /// @param _b The unsigned integer to reverse
- /// @return The reversed value
- function reverseUint256(uint256 _b) internal pure returns (uint256 v) {
- v = _b;
-
- // swap bytes
- v = ((v >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) |
- ((v & 0x00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF00FF) << 8);
- // swap 2-byte long pairs
- v = ((v >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) |
- ((v & 0x0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF0000FFFF) << 16);
- // swap 4-byte long pairs
- v = ((v >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) |
- ((v & 0x00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF00000000FFFFFFFF) << 32);
- // swap 8-byte long pairs
- v = ((v >> 64) & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) |
- ((v & 0x0000000000000000FFFFFFFFFFFFFFFF0000000000000000FFFFFFFFFFFFFFFF) << 64);
- // swap 16-byte long pairs
- v = (v >> 128) | (v << 128);
- }
-
- /// @notice Converts big-endian bytes to a uint
- /// @dev Traverses the byte array and sums the bytes
- /// @param _b The big-endian bytes-encoded integer
- /// @return The integer representation
- function bytesToUint(bytes memory _b) internal pure returns (uint256) {
- uint256 _number;
-
- for (uint i = 0; i < _b.length; i++) {
- _number = _number + uint8(_b[i]) * (2 ** (8 * (_b.length - (i + 1))));
- }
-
- return _number;
- }
-
- /// @notice Get the last _num bytes from a byte array
- /// @param _b The byte array to slice
- /// @param _num The number of bytes to extract from the end
- /// @return The last _num bytes of _b
- function lastBytes(bytes memory _b, uint256 _num) internal pure returns (bytes memory) {
- uint256 _start = _b.length.sub(_num);
-
- return _b.slice(_start, _num);
- }
-
- /// @notice Implements bitcoin's hash160 (rmd160(sha2()))
- /// @dev abi.encodePacked changes the return to bytes instead of bytes32
- /// @param _b The pre-image
- /// @return The digest
- function hash160(bytes memory _b) internal pure returns (bytes memory) {
- return abi.encodePacked(ripemd160(abi.encodePacked(sha256(_b))));
- }
-
- /// @notice Implements bitcoin's hash256 (double sha2)
- /// @dev abi.encodePacked changes the return to bytes instead of bytes32
- /// @param _b The pre-image
- /// @return The digest
- function hash256(bytes memory _b) internal pure returns (bytes32) {
- return sha256(abi.encodePacked(sha256(_b)));
- }
-
- /// @notice Implements bitcoin's hash256 (double sha2)
- /// @dev sha2 is precompiled smart contract located at address(2)
- /// @param _b The pre-image
- /// @return The digest
- function hash256View(bytes memory _b) internal view returns (bytes32 res) {
- // solium-disable-next-line security/no-inline-assembly
- assembly {
- let ptr := mload(0x40)
- pop(staticcall(gas, 2, add(_b, 32), mload(_b), ptr, 32))
- pop(staticcall(gas, 2, ptr, 32, ptr, 32))
- res := mload(ptr)
- }
- }
-
- /* ************ */
- /* Legacy Input */
- /* ************ */
-
- /// @notice Extracts the nth input from the vin (0-indexed)
- /// @dev Iterates over the vin. If you need to extract several, write a custom function
- /// @param _vin The vin as a tightly-packed byte array
- /// @param _index The 0-indexed location of the input to extract
- /// @return The input as a byte array
- function extractInputAtIndex(bytes memory _vin, uint256 _index) internal pure returns (bytes memory) {
- uint256 _varIntDataLen;
- uint256 _nIns;
-
- (_varIntDataLen, _nIns) = parseVarInt(_vin);
- require(_varIntDataLen != ERR_BAD_ARG, "Read overrun during VarInt parsing");
- require(_index < _nIns, "Vin read overrun");
-
- bytes memory _remaining;
-
- uint256 _len = 0;
- uint256 _offset = 1 + _varIntDataLen;
-
- for (uint256 _i = 0; _i < _index; _i ++) {
- _remaining = _vin.slice(_offset, _vin.length - _offset);
- _len = determineInputLength(_remaining);
- require(_len != ERR_BAD_ARG, "Bad VarInt in scriptSig");
- _offset = _offset + _len;
- }
-
- _remaining = _vin.slice(_offset, _vin.length - _offset);
- _len = determineInputLength(_remaining);
- require(_len != ERR_BAD_ARG, "Bad VarInt in scriptSig");
- return _vin.slice(_offset, _len);
- }
-
- /// @notice Determines whether an input is legacy
- /// @dev False if no scriptSig, otherwise True
- /// @param _input The input
- /// @return True for legacy, False for witness
- function isLegacyInput(bytes memory _input) internal pure returns (bool) {
- return _input.keccak256Slice(36, 1) != keccak256(hex"00");
- }
-
- /// @notice Determines the length of a scriptSig in an input
- /// @dev Will return 0 if passed a witness input.
- /// @param _input The LEGACY input
- /// @return The length of the script sig
- function extractScriptSigLen(bytes memory _input) internal pure returns (uint256, uint256) {
- if (_input.length < 37) {
- return (ERR_BAD_ARG, 0);
- }
- bytes memory _afterOutpoint = _input.slice(36, _input.length - 36);
-
- uint256 _varIntDataLen;
- uint256 _scriptSigLen;
- (_varIntDataLen, _scriptSigLen) = parseVarInt(_afterOutpoint);
-
- return (_varIntDataLen, _scriptSigLen);
- }
-
- /// @notice Determines the length of an input from its scriptSig
- /// @dev 36 for outpoint, 1 for scriptSig length, 4 for sequence
- /// @param _input The input
- /// @return The length of the input in bytes
- function determineInputLength(bytes memory _input) internal pure returns (uint256) {
- uint256 _varIntDataLen;
- uint256 _scriptSigLen;
- (_varIntDataLen, _scriptSigLen) = extractScriptSigLen(_input);
- if (_varIntDataLen == ERR_BAD_ARG) {
- return ERR_BAD_ARG;
- }
-
- return 36 + 1 + _varIntDataLen + _scriptSigLen + 4;
- }
-
- /// @notice Extracts the LE sequence bytes from an input
- /// @dev Sequence is used for relative time locks
- /// @param _input The LEGACY input
- /// @return The sequence bytes (LE uint)
- function extractSequenceLELegacy(bytes memory _input) internal pure returns (bytes memory) {
- uint256 _varIntDataLen;
- uint256 _scriptSigLen;
- (_varIntDataLen, _scriptSigLen) = extractScriptSigLen(_input);
- require(_varIntDataLen != ERR_BAD_ARG, "Bad VarInt in scriptSig");
- return _input.slice(36 + 1 + _varIntDataLen + _scriptSigLen, 4);
- }
-
- /// @notice Extracts the sequence from the input
- /// @dev Sequence is a 4-byte little-endian number
- /// @param _input The LEGACY input
- /// @return The sequence number (big-endian uint)
- function extractSequenceLegacy(bytes memory _input) internal pure returns (uint32) {
- bytes memory _leSeqence = extractSequenceLELegacy(_input);
- bytes memory _beSequence = reverseEndianness(_leSeqence);
- return uint32(bytesToUint(_beSequence));
- }
- /// @notice Extracts the VarInt-prepended scriptSig from the input in a tx
- /// @dev Will return hex"00" if passed a witness input
- /// @param _input The LEGACY input
- /// @return The length-prepended scriptSig
- function extractScriptSig(bytes memory _input) internal pure returns (bytes memory) {
- uint256 _varIntDataLen;
- uint256 _scriptSigLen;
- (_varIntDataLen, _scriptSigLen) = extractScriptSigLen(_input);
- require(_varIntDataLen != ERR_BAD_ARG, "Bad VarInt in scriptSig");
- return _input.slice(36, 1 + _varIntDataLen + _scriptSigLen);
- }
-
-
- /* ************* */
- /* Witness Input */
- /* ************* */
-
- /// @notice Extracts the LE sequence bytes from an input
- /// @dev Sequence is used for relative time locks
- /// @param _input The WITNESS input
- /// @return The sequence bytes (LE uint)
- function extractSequenceLEWitness(bytes memory _input) internal pure returns (bytes memory) {
- return _input.slice(37, 4);
- }
-
- /// @notice Extracts the sequence from the input in a tx
- /// @dev Sequence is a 4-byte little-endian number
- /// @param _input The WITNESS input
- /// @return The sequence number (big-endian uint)
- function extractSequenceWitness(bytes memory _input) internal pure returns (uint32) {
- bytes memory _leSeqence = extractSequenceLEWitness(_input);
- bytes memory _inputeSequence = reverseEndianness(_leSeqence);
- return uint32(bytesToUint(_inputeSequence));
- }
-
- /// @notice Extracts the outpoint from the input in a tx
- /// @dev 32-byte tx id with 4-byte index
- /// @param _input The input
- /// @return The outpoint (LE bytes of prev tx hash + LE bytes of prev tx index)
- function extractOutpoint(bytes memory _input) internal pure returns (bytes memory) {
- return _input.slice(0, 36);
- }
-
- /// @notice Extracts the outpoint tx id from an input
- /// @dev 32-byte tx id
- /// @param _input The input
- /// @return The tx id (little-endian bytes)
- function extractInputTxIdLE(bytes memory _input) internal pure returns (bytes32) {
- return _input.slice(0, 32).toBytes32();
- }
-
- /// @notice Extracts the LE tx input index from the input in a tx
- /// @dev 4-byte tx index
- /// @param _input The input
- /// @return The tx index (little-endian bytes)
- function extractTxIndexLE(bytes memory _input) internal pure returns (bytes memory) {
- return _input.slice(32, 4);
- }
-
- /* ****** */
- /* Output */
- /* ****** */
-
- /// @notice Determines the length of an output
- /// @dev Works with any properly formatted output
- /// @param _output The output
- /// @return The length indicated by the prefix, error if invalid length
- function determineOutputLength(bytes memory _output) internal pure returns (uint256) {
- if (_output.length < 9) {
- return ERR_BAD_ARG;
- }
- bytes memory _afterValue = _output.slice(8, _output.length - 8);
-
- uint256 _varIntDataLen;
- uint256 _scriptPubkeyLength;
- (_varIntDataLen, _scriptPubkeyLength) = parseVarInt(_afterValue);
-
- if (_varIntDataLen == ERR_BAD_ARG) {
- return ERR_BAD_ARG;
- }
-
- // 8-byte value, 1-byte for tag itself
- return 8 + 1 + _varIntDataLen + _scriptPubkeyLength;
- }
-
- /// @notice Extracts the output at a given index in the TxOuts vector
- /// @dev Iterates over the vout. If you need to extract multiple, write a custom function
- /// @param _vout The _vout to extract from
- /// @param _index The 0-indexed location of the output to extract
- /// @return The specified output
- function extractOutputAtIndex(bytes memory _vout, uint256 _index) internal pure returns (bytes memory) {
- uint256 _varIntDataLen;
- uint256 _nOuts;
-
- (_varIntDataLen, _nOuts) = parseVarInt(_vout);
- require(_varIntDataLen != ERR_BAD_ARG, "Read overrun during VarInt parsing");
- require(_index < _nOuts, "Vout read overrun");
-
- bytes memory _remaining;
-
- uint256 _len = 0;
- uint256 _offset = 1 + _varIntDataLen;
-
- for (uint256 _i = 0; _i < _index; _i ++) {
- _remaining = _vout.slice(_offset, _vout.length - _offset);
- _len = determineOutputLength(_remaining);
- require(_len != ERR_BAD_ARG, "Bad VarInt in scriptPubkey");
- _offset += _len;
- }
-
- _remaining = _vout.slice(_offset, _vout.length - _offset);
- _len = determineOutputLength(_remaining);
- require(_len != ERR_BAD_ARG, "Bad VarInt in scriptPubkey");
- return _vout.slice(_offset, _len);
- }
-
- /// @notice Extracts the value bytes from the output in a tx
- /// @dev Value is an 8-byte little-endian number
- /// @param _output The output
- /// @return The output value as LE bytes
- function extractValueLE(bytes memory _output) internal pure returns (bytes memory) {
- return _output.slice(0, 8);
- }
-
- /// @notice Extracts the value from the output in a tx
- /// @dev Value is an 8-byte little-endian number
- /// @param _output The output
- /// @return The output value
- function extractValue(bytes memory _output) internal pure returns (uint64) {
- bytes memory _leValue = extractValueLE(_output);
- bytes memory _beValue = reverseEndianness(_leValue);
- return uint64(bytesToUint(_beValue));
- }
-
- /// @notice Extracts the data from an op return output
- /// @dev Returns hex"" if no data or not an op return
- /// @param _output The output
- /// @return Any data contained in the opreturn output, null if not an op return
- function extractOpReturnData(bytes memory _output) internal pure returns (bytes memory) {
- if (_output.keccak256Slice(9, 1) != keccak256(hex"6a")) {
- return hex"";
- }
- bytes memory _dataLen = _output.slice(10, 1);
- return _output.slice(11, bytesToUint(_dataLen));
- }
-
- /// @notice Extracts the hash from the output script
- /// @dev Determines type by the length prefix and validates format
- /// @param _output The output
- /// @return The hash committed to by the pk_script, or null for errors
- function extractHash(bytes memory _output) internal pure returns (bytes memory) {
- uint8 _scriptLen = uint8(_output[8]);
-
- // don't have to worry about overflow here.
- // if _scriptLen + 9 overflows, then output.length would have to be < 9
- // for this check to pass. if it's < 9, then we errored when assigning
- // _scriptLen
- if (_scriptLen + 9 != _output.length) {
- return hex"";
- }
-
- if (uint8(_output[9]) == 0) {
- if (_scriptLen < 2) {
- return hex"";
- }
- uint256 _payloadLen = uint8(_output[10]);
- // Check for maliciously formatted witness outputs.
- // No need to worry about underflow as long b/c of the `< 2` check
- if (_payloadLen != _scriptLen - 2 || (_payloadLen != 0x20 && _payloadLen != 0x14)) {
- return hex"";
- }
- return _output.slice(11, _payloadLen);
- } else {
- bytes32 _tag = _output.keccak256Slice(8, 3);
- // p2pkh
- if (_tag == keccak256(hex"1976a9")) {
- // Check for maliciously formatted p2pkh
- // No need to worry about underflow, b/c of _scriptLen check
- if (uint8(_output[11]) != 0x14 ||
- _output.keccak256Slice(_output.length - 2, 2) != keccak256(hex"88ac")) {
- return hex"";
- }
- return _output.slice(12, 20);
- //p2sh
- } else if (_tag == keccak256(hex"17a914")) {
- // Check for maliciously formatted p2sh
- // No need to worry about underflow, b/c of _scriptLen check
- if (uint8(_output[_output.length - 1]) != 0x87) {
- return hex"";
- }
- return _output.slice(11, 20);
- }
- }
- return hex""; /* NB: will trigger on OPRETURN and any non-standard that doesn't overrun */
- }
-
- /* ********** */
- /* Witness TX */
- /* ********** */
-
-
- /// @notice Checks that the vin passed up is properly formatted
- /// @dev Consider a vin with a valid vout in its scriptsig
- /// @param _vin Raw bytes length-prefixed input vector
- /// @return True if it represents a validly formatted vin
- function validateVin(bytes memory _vin) internal pure returns (bool) {
- uint256 _varIntDataLen;
- uint256 _nIns;
-
- (_varIntDataLen, _nIns) = parseVarInt(_vin);
-
- // Not valid if it says there are too many or no inputs
- if (_nIns == 0 || _varIntDataLen == ERR_BAD_ARG) {
- return false;
- }
-
- uint256 _offset = 1 + _varIntDataLen;
-
- for (uint256 i = 0; i < _nIns; i++) {
- // If we're at the end, but still expect more
- if (_offset >= _vin.length) {
- return false;
- }
-
- // Grab the next input and determine its length.
- bytes memory _next = _vin.slice(_offset, _vin.length - _offset);
- uint256 _nextLen = determineInputLength(_next);
- if (_nextLen == ERR_BAD_ARG) {
- return false;
- }
-
- // Increase the offset by that much
- _offset += _nextLen;
- }
-
- // Returns false if we're not exactly at the end
- return _offset == _vin.length;
- }
-
- /// @notice Checks that the vout passed up is properly formatted
- /// @dev Consider a vout with a valid scriptpubkey
- /// @param _vout Raw bytes length-prefixed output vector
- /// @return True if it represents a validly formatted vout
- function validateVout(bytes memory _vout) internal pure returns (bool) {
- uint256 _varIntDataLen;
- uint256 _nOuts;
-
- (_varIntDataLen, _nOuts) = parseVarInt(_vout);
-
- // Not valid if it says there are too many or no outputs
- if (_nOuts == 0 || _varIntDataLen == ERR_BAD_ARG) {
- return false;
- }
-
- uint256 _offset = 1 + _varIntDataLen;
-
- for (uint256 i = 0; i < _nOuts; i++) {
- // If we're at the end, but still expect more
- if (_offset >= _vout.length) {
- return false;
- }
-
- // Grab the next output and determine its length.
- // Increase the offset by that much
- bytes memory _next = _vout.slice(_offset, _vout.length - _offset);
- uint256 _nextLen = determineOutputLength(_next);
- if (_nextLen == ERR_BAD_ARG) {
- return false;
- }
-
- _offset += _nextLen;
- }
-
- // Returns false if we're not exactly at the end
- return _offset == _vout.length;
- }
-
-
-
- /* ************ */
- /* Block Header */
- /* ************ */
-
- /// @notice Extracts the transaction merkle root from a block header
- /// @dev Use verifyHash256Merkle to verify proofs with this root
- /// @param _header The header
- /// @return The merkle root (little-endian)
- function extractMerkleRootLE(bytes memory _header) internal pure returns (bytes memory) {
- return _header.slice(36, 32);
- }
-
- /// @notice Extracts the target from a block header
- /// @dev Target is a 256-bit number encoded as a 3-byte mantissa and 1-byte exponent
- /// @param _header The header
- /// @return The target threshold
- function extractTarget(bytes memory _header) internal pure returns (uint256) {
- bytes memory _m = _header.slice(72, 3);
- uint8 _e = uint8(_header[75]);
- uint256 _mantissa = bytesToUint(reverseEndianness(_m));
- uint _exponent = _e - 3;
-
- return _mantissa * (256 ** _exponent);
- }
-
- /// @notice Calculate difficulty from the difficulty 1 target and current target
- /// @dev Difficulty 1 is 0x1d00ffff on mainnet and testnet
- /// @dev Difficulty 1 is a 256-bit number encoded as a 3-byte mantissa and 1-byte exponent
- /// @param _target The current target
- /// @return The block difficulty (bdiff)
- function calculateDifficulty(uint256 _target) internal pure returns (uint256) {
- // Difficulty 1 calculated from 0x1d00ffff
- return DIFF1_TARGET.div(_target);
- }
-
- /// @notice Extracts the previous block's hash from a block header
- /// @dev Block headers do NOT include block number :(
- /// @param _header The header
- /// @return The previous block's hash (little-endian)
- function extractPrevBlockLE(bytes memory _header) internal pure returns (bytes memory) {
- return _header.slice(4, 32);
- }
-
- /// @notice Extracts the timestamp from a block header
- /// @dev Time is not 100% reliable
- /// @param _header The header
- /// @return The timestamp (little-endian bytes)
- function extractTimestampLE(bytes memory _header) internal pure returns (bytes memory) {
- return _header.slice(68, 4);
- }
-
- /// @notice Extracts the timestamp from a block header
- /// @dev Time is not 100% reliable
- /// @param _header The header
- /// @return The timestamp (uint)
- function extractTimestamp(bytes memory _header) internal pure returns (uint32) {
- return uint32(bytesToUint(reverseEndianness(extractTimestampLE(_header))));
- }
-
- /// @notice Extracts the expected difficulty from a block header
- /// @dev Does NOT verify the work
- /// @param _header The header
- /// @return The difficulty as an integer
- function extractDifficulty(bytes memory _header) internal pure returns (uint256) {
- return calculateDifficulty(extractTarget(_header));
- }
-
- /// @notice Concatenates and hashes two inputs for merkle proving
- /// @param _a The first hash
- /// @param _b The second hash
- /// @return The double-sha256 of the concatenated hashes
- function _hash256MerkleStep(bytes memory _a, bytes memory _b) internal pure returns (bytes32) {
- return hash256(abi.encodePacked(_a, _b));
- }
-
- /// @notice Verifies a Bitcoin-style merkle tree
- /// @dev Leaves are 0-indexed.
- /// @param _proof The proof. Tightly packed LE sha256 hashes. The last hash is the root
- /// @param _index The index of the leaf
- /// @return true if the proof is valid, else false
- function verifyHash256Merkle(bytes memory _proof, uint _index) internal pure returns (bool) {
- // Not an even number of hashes
- if (_proof.length % 32 != 0) {
- return false;
- }
-
- // Special case for coinbase-only blocks
- if (_proof.length == 32) {
- return true;
- }
-
- // Should never occur
- if (_proof.length == 64) {
- return false;
- }
-
- uint _idx = _index;
- bytes32 _root = _proof.slice(_proof.length - 32, 32).toBytes32();
- bytes32 _current = _proof.slice(0, 32).toBytes32();
-
- for (uint i = 1; i < (_proof.length.div(32)) - 1; i++) {
- if (_idx % 2 == 1) {
- _current = _hash256MerkleStep(_proof.slice(i * 32, 32), abi.encodePacked(_current));
- } else {
- _current = _hash256MerkleStep(abi.encodePacked(_current), _proof.slice(i * 32, 32));
- }
- _idx = _idx >> 1;
- }
- return _current == _root;
- }
-
- /*
- NB: https://github.com/bitcoin/bitcoin/blob/78dae8caccd82cfbfd76557f1fb7d7557c7b5edb/src/pow.cpp#L49-L72
- NB: We get a full-bitlength target from this. For comparison with
- header-encoded targets we need to mask it with the header target
- e.g. (full & truncated) == truncated
- */
- /// @notice performs the bitcoin difficulty retarget
- /// @dev implements the Bitcoin algorithm precisely
- /// @param _previousTarget the target of the previous period
- /// @param _firstTimestamp the timestamp of the first block in the difficulty period
- /// @param _secondTimestamp the timestamp of the last block in the difficulty period
- /// @return the new period's target threshold
- function retargetAlgorithm(
- uint256 _previousTarget,
- uint256 _firstTimestamp,
- uint256 _secondTimestamp
- ) internal pure returns (uint256) {
- uint256 _elapsedTime = _secondTimestamp.sub(_firstTimestamp);
-
- // Normalize ratio to factor of 4 if very long or very short
- if (_elapsedTime < RETARGET_PERIOD.div(4)) {
- _elapsedTime = RETARGET_PERIOD.div(4);
- }
- if (_elapsedTime > RETARGET_PERIOD.mul(4)) {
- _elapsedTime = RETARGET_PERIOD.mul(4);
- }
-
- /*
- NB: high targets e.g. ffff0020 can cause overflows here
- so we divide it by 256**2, then multiply by 256**2 later
- we know the target is evenly divisible by 256**2, so this isn't an issue
- */
-
- uint256 _adjusted = _previousTarget.div(65536).mul(_elapsedTime);
- return _adjusted.div(RETARGET_PERIOD).mul(65536);
- }
-}
diff --git a/example/errors/Contract63.sol b/example/errors/Contract63.sol
deleted file mode 100644
index 7bfab98..0000000
--- a/example/errors/Contract63.sol
+++ /dev/null
@@ -1,511 +0,0 @@
-// SPDX-License-Identifier: MIT OR Apache-2.0
-
-pragma solidity ^0.8.0;
-
-import "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
-import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
-
-import "./interfaces/ICollectionContractInitializer.sol";
-import "./interfaces/ICollectionFactory.sol";
-import "./interfaces/IGetRoyalties.sol";
-import "./interfaces/IProxyCall.sol";
-import "./interfaces/ITokenCreator.sol";
-import "./interfaces/ITokenCreatorPaymentAddress.sol";
-import "./interfaces/IGetFees.sol";
-
-import "./libraries/AccountMigrationLibrary.sol";
-import "./libraries/ProxyCall.sol";
-import "./libraries/BytesLibrary.sol";
-import "./interfaces/IRoyaltyInfo.sol";
-
-/**
- * @title A collection of NFTs.
- * @notice All NFTs from this contract are minted by the same creator.
- * A 10% royalty to the creator is included which may be split with collaborators.
- */
-contract CollectionContract is
- ICollectionContractInitializer,
- IGetRoyalties,
- IGetFees,
- IRoyaltyInfo,
- ITokenCreator,
- ITokenCreatorPaymentAddress,
- ERC721BurnableUpgradeable
-{
- using AccountMigrationLibrary for address;
- using AddressUpgradeable for address;
- using BytesLibrary for bytes;
- using ProxyCall for IProxyCall;
-
- uint256 private constant ROYALTY_IN_BASIS_POINTS = 1000;
- uint256 private constant ROYALTY_RATIO = 10;
-
- /**
- * @notice The baseURI to use for the tokenURI, if undefined then `ipfs://` is used.
- */
- string private baseURI_;
-
- /**
- * @dev Stores hashes minted to prevent duplicates.
- */
- mapping(string => bool) private cidToMinted;
-
- /**
- * @notice The factory which was used to create this collection.
- * @dev This is used to read common config.
- */
- ICollectionFactory public immutable collectionFactory;
-
- /**
- * @notice The tokenId of the most recently created NFT.
- * @dev Minting starts at tokenId 1. Each mint will use this value + 1.
- */
- uint256 public latestTokenId;
-
- /**
- * @notice The max tokenId which can be minted, or 0 if there's no limit.
- * @dev This value may be set at any time, but once set it cannot be increased.
- */
- uint256 public maxTokenId;
-
- /**
- * @notice The owner/creator of this NFT collection.
- */
- address payable public owner;
-
- /**
- * @dev Stores an optional alternate address to receive creator revenue and royalty payments.
- * The target address may be a contract which could split or escrow payments.
- */
- mapping(uint256 => address payable) private tokenIdToCreatorPaymentAddress;
-
- /**
- * @dev Tracks how many tokens have been burned, used to calc the total supply efficiently.
- */
- uint256 private burnCounter;
-
- /**
- * @dev Stores a CID for each NFT.
- */
- mapping(uint256 => string) private _tokenCIDs;
-
- event BaseURIUpdated(string baseURI);
- event CreatorMigrated(address indexed originalAddress, address indexed newAddress);
- event MaxTokenIdUpdated(uint256 indexed maxTokenId);
- event Minted(address indexed creator, uint256 indexed tokenId, string indexed indexedTokenCID, string tokenCID);
- event NFTOwnerMigrated(uint256 indexed tokenId, address indexed originalAddress, address indexed newAddress);
- event PaymentAddressMigrated(
- uint256 indexed tokenId,
- address indexed originalAddress,
- address indexed newAddress,
- address originalPaymentAddress,
- address newPaymentAddress
- );
- event SelfDestruct(address indexed owner);
- event TokenCreatorPaymentAddressSet(
- address indexed fromPaymentAddress,
- address indexed toPaymentAddress,
- uint256 indexed tokenId
- );
-
- modifier onlyOwner() {
- require(msg.sender == owner, "CollectionContract: Caller is not owner");
- _;
- }
-
- modifier onlyOperator() {
- require(collectionFactory.rolesContract().isOperator(msg.sender), "CollectionContract: Caller is not an operator");
- _;
- }
-
- /**
- * @dev The constructor for a proxy can only be used to assign immutable variables.
- */
- constructor(address _collectionFactory) {
- require(_collectionFactory.isContract(), "CollectionContract: collectionFactory is not a contract");
- collectionFactory = ICollectionFactory(_collectionFactory);
- }
-
- /**
- * @notice Called by the factory on creation.
- * @dev This may only be called once.
- */
- function initialize(
- address payable _creator,
- string memory _name,
- string memory _symbol
- ) external initializer {
- require(msg.sender == address(collectionFactory), "CollectionContract: Collection must be created via the factory");
-
- __ERC721_init_unchained(_name, _symbol);
-
- owner = _creator;
- }
-
- /**
- * @notice Allows the owner to mint an NFT defined by its metadata path.
- */
- function mint(string memory tokenCID) public returns (uint256 tokenId) {
- tokenId = _mint(tokenCID);
- }
-
- /**
- * @notice Allows the owner to mint and sets approval for all for the provided operator.
- * @dev This can be used by creators the first time they mint an NFT to save having to issue a separate approval
- * transaction before starting an auction.
- */
- function mintAndApprove(string memory tokenCID, address operator) public returns (uint256 tokenId) {
- tokenId = _mint(tokenCID);
- setApprovalForAll(operator, true);
- }
-
- /**
- * @notice Allows the owner to mint an NFT and have creator revenue/royalties sent to an alternate address.
- */
- function mintWithCreatorPaymentAddress(string memory tokenCID, address payable tokenCreatorPaymentAddress)
- public
- returns (uint256 tokenId)
- {
- require(tokenCreatorPaymentAddress != address(0), "CollectionContract: tokenCreatorPaymentAddress is required");
- tokenId = mint(tokenCID);
- _setTokenCreatorPaymentAddress(tokenId, tokenCreatorPaymentAddress);
- }
-
- /**
- * @notice Allows the owner to mint an NFT and have creator revenue/royalties sent to an alternate address.
- * Also sets approval for all for the provided operator.
- * @dev This can be used by creators the first time they mint an NFT to save having to issue a separate approval
- * transaction before starting an auction.
- */
- function mintWithCreatorPaymentAddressAndApprove(
- string memory tokenCID,
- address payable tokenCreatorPaymentAddress,
- address operator
- ) public returns (uint256 tokenId) {
- tokenId = mintWithCreatorPaymentAddress(tokenCID, tokenCreatorPaymentAddress);
- setApprovalForAll(operator, true);
- }
-
- /**
- * @notice Allows the owner to mint an NFT and have creator revenue/royalties sent to an alternate address
- * which is defined by a contract call, typically a proxy contract address representing the payment terms.
- * @param paymentAddressFactory The contract to call which will return the address to use for payments.
- * @param paymentAddressCallData The call details to sent to the factory provided.
- */
- function mintWithCreatorPaymentFactory(
- string memory tokenCID,
- address paymentAddressFactory,
- bytes memory paymentAddressCallData
- ) public returns (uint256 tokenId) {
- address payable tokenCreatorPaymentAddress = collectionFactory
- .proxyCallContract()
- .proxyCallAndReturnContractAddress(paymentAddressFactory, paymentAddressCallData);
- tokenId = mintWithCreatorPaymentAddress(tokenCID, tokenCreatorPaymentAddress);
- }
-
- /**
- * @notice Allows the owner to mint an NFT and have creator revenue/royalties sent to an alternate address
- * which is defined by a contract call, typically a proxy contract address representing the payment terms.
- * Also sets approval for all for the provided operator.
- * @param paymentAddressFactory The contract to call which will return the address to use for payments.
- * @param paymentAddressCallData The call details to sent to the factory provided.
- * @dev This can be used by creators the first time they mint an NFT to save having to issue a separate approval
- * transaction before starting an auction.
- */
- function mintWithCreatorPaymentFactoryAndApprove(
- string memory tokenCID,
- address paymentAddressFactory,
- bytes memory paymentAddressCallData,
- address operator
- ) public returns (uint256 tokenId) {
- tokenId = mintWithCreatorPaymentFactory(tokenCID, paymentAddressFactory, paymentAddressCallData);
- setApprovalForAll(operator, true);
- }
-
- /**
- * @notice Allows the owner to set a max tokenID.
- * This provides a guarantee to collectors about the limit of this collection contract, if applicable.
- * @dev Once this value has been set, it may be decreased but can never be increased.
- */
- function updateMaxTokenId(uint256 _maxTokenId) external onlyOwner {
- require(_maxTokenId > 0, "CollectionContract: Max token ID may not be cleared");
- require(maxTokenId == 0 || _maxTokenId < maxTokenId, "CollectionContract: Max token ID may not increase");
- require(latestTokenId + 1 <= _maxTokenId, "CollectionContract: Max token ID must be greater than last mint");
- maxTokenId = _maxTokenId;
-
- emit MaxTokenIdUpdated(_maxTokenId);
- }
-
- /**
- * @notice Allows the owner to assign a baseURI to use for the tokenURI instead of the default `ipfs://`.
- */
- function updateBaseURI(string calldata baseURIOverride) external onlyOwner {
- baseURI_ = baseURIOverride;
-
- emit BaseURIUpdated(baseURIOverride);
- }
-
- /**
- * @notice Allows the creator to burn if they currently own the NFT.
- */
- function burn(uint256 tokenId) public override onlyOwner {
- super.burn(tokenId);
- }
-
- /**
- * @notice Allows the collection owner to destroy this contract only if
- * no NFTs have been minted yet.
- */
- function selfDestruct() external onlyOwner {
- require(totalSupply() == 0, "CollectionContract: Any NFTs minted must be burned first");
- emit SelfDestruct(msg.sender);
- selfdestruct(payable(msg.sender));
- }
-
- /**
- * @notice Allows an NFT owner or creator and Foundation to work together in order to update the creator
- * to a new account and/or transfer NFTs to that account.
- * @param signature Message `I authorize Foundation to migrate my account to ${newAccount.address.toLowerCase()}`
- * signed by the original account.
- * @dev This will gracefully skip any NFTs that have been burned or transferred.
- */
- function adminAccountMigration(
- uint256[] calldata ownedTokenIds,
- address originalAddress,
- address payable newAddress,
- bytes calldata signature
- ) public onlyOperator {
- originalAddress.requireAuthorizedAccountMigration(newAddress, signature);
-
- for (uint256 i = 0; i < ownedTokenIds.length; i++) {
- uint256 tokenId = ownedTokenIds[i];
- // Check that the token exists and still is owned by the originalAddress
- // so that frontrunning a burn or transfer will not cause the entire tx to revert
- if (_exists(tokenId) && ownerOf(tokenId) == originalAddress) {
- _transfer(originalAddress, newAddress, tokenId);
- emit NFTOwnerMigrated(tokenId, originalAddress, newAddress);
- }
- }
-
- if (owner == originalAddress) {
- owner = newAddress;
- emit CreatorMigrated(originalAddress, newAddress);
- }
- }
-
- /**
- * @notice Allows a split recipient and Foundation to work together in order to update the payment address
- * to a new account.
- * @param signature Message `I authorize Foundation to migrate my account to ${newAccount.address.toLowerCase()}`
- * signed by the original account.
- */
- function adminAccountMigrationForPaymentAddresses(
- uint256[] calldata paymentAddressTokenIds,
- address paymentAddressFactory,
- bytes memory paymentAddressCallData,
- uint256 addressLocationInCallData,
- address originalAddress,
- address payable newAddress,
- bytes calldata signature
- ) public onlyOperator {
- originalAddress.requireAuthorizedAccountMigration(newAddress, signature);
- _adminAccountRecoveryForPaymentAddresses(
- paymentAddressTokenIds,
- paymentAddressFactory,
- paymentAddressCallData,
- addressLocationInCallData,
- originalAddress,
- newAddress
- );
- }
-
- function baseURI() external view returns (string memory) {
- return _baseURI();
- }
-
- /**
- * @notice Returns an array of recipient addresses to which royalties for secondary sales should be sent.
- * The expected royalty amount is communicated with `getFeeBps`.
- */
- function getFeeRecipients(uint256 id) external view returns (address payable[] memory recipients) {
- recipients = new address payable[](1);
- recipients[0] = getTokenCreatorPaymentAddress(id);
- }
-
- /**
- * @notice Returns an array of royalties to be sent for secondary sales in basis points.
- * The expected recipients is communicated with `getFeeRecipients`.
- */
- function getFeeBps(
- uint256 /* id */
- ) external pure returns (uint256[] memory feesInBasisPoints) {
- feesInBasisPoints = new uint256[](1);
- feesInBasisPoints[0] = ROYALTY_IN_BASIS_POINTS;
- }
-
- /**
- * @notice Checks if the creator has already minted a given NFT using this collection contract.
- */
- function getHasMintedCID(string memory tokenCID) public view returns (bool) {
- return cidToMinted[tokenCID];
- }
-
- /**
- * @notice Returns an array of royalties to be sent for secondary sales.
- */
- function getRoyalties(uint256 tokenId)
- external
- view
- returns (address payable[] memory recipients, uint256[] memory feesInBasisPoints)
- {
- recipients = new address payable[](1);
- recipients[0] = getTokenCreatorPaymentAddress(tokenId);
- feesInBasisPoints = new uint256[](1);
- feesInBasisPoints[0] = ROYALTY_IN_BASIS_POINTS;
- }
-
- /**
- * @notice Returns the receiver and the amount to be sent for a secondary sale.
- */
- function royaltyInfo(uint256 _tokenId, uint256 _salePrice)
- external
- view
- returns (address receiver, uint256 royaltyAmount)
- {
- receiver = getTokenCreatorPaymentAddress(_tokenId);
- unchecked {
- royaltyAmount = _salePrice / ROYALTY_RATIO;
- }
- }
-
- /**
- * @notice Returns the creator for an NFT, which is always the collection owner.
- */
- function tokenCreator(
- uint256 /* tokenId */
- ) external view returns (address payable) {
- return owner;
- }
-
- /**
- * @notice Returns the desired payment address to be used for any transfers to the creator.
- * @dev The payment address may be assigned for each individual NFT, if not defined the collection owner is returned.
- */
- function getTokenCreatorPaymentAddress(uint256 tokenId)
- public
- view
- returns (address payable tokenCreatorPaymentAddress)
- {
- tokenCreatorPaymentAddress = tokenIdToCreatorPaymentAddress[tokenId];
- if (tokenCreatorPaymentAddress == address(0)) {
- tokenCreatorPaymentAddress = owner;
- }
- }
-
- /**
- * @notice Count of NFTs tracked by this contract.
- * @dev From the ERC-721 enumerable standard.
- */
- function totalSupply() public view returns (uint256) {
- unchecked {
- return latestTokenId - burnCounter;
- }
- }
-
- function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
- if (
- interfaceId == type(IGetRoyalties).interfaceId ||
- interfaceId == type(ITokenCreator).interfaceId ||
- interfaceId == type(ITokenCreatorPaymentAddress).interfaceId ||
- interfaceId == type(IGetFees).interfaceId ||
- interfaceId == type(IRoyaltyInfo).interfaceId
- ) {
- return true;
- }
- return super.supportsInterface(interfaceId);
- }
-
- function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
- require(_exists(tokenId), "CollectionContract: URI query for nonexistent token");
-
- return string(abi.encodePacked(_baseURI(), _tokenCIDs[tokenId]));
- }
-
- function _mint(string memory tokenCID) private onlyOwner returns (uint256 tokenId) {
- require(bytes(tokenCID).length > 0, "CollectionContract: tokenCID is required");
- require(!cidToMinted[tokenCID], "CollectionContract: NFT was already minted");
- unchecked {
- tokenId = ++latestTokenId;
- require(maxTokenId == 0 || tokenId <= maxTokenId, "CollectionContract: Max token count has already been minted");
- cidToMinted[tokenCID] = true;
- _tokenCIDs[tokenId] = tokenCID;
- _safeMint(msg.sender, tokenId, "");
- emit Minted(msg.sender, tokenId, tokenCID, tokenCID);
- }
- }
-
- /**
- * @dev Allow setting a different address to send payments to for both primary sale revenue
- * and secondary sales royalties.
- */
- function _setTokenCreatorPaymentAddress(uint256 tokenId, address payable tokenCreatorPaymentAddress) internal {
- emit TokenCreatorPaymentAddressSet(tokenIdToCreatorPaymentAddress[tokenId], tokenCreatorPaymentAddress, tokenId);
- tokenIdToCreatorPaymentAddress[tokenId] = tokenCreatorPaymentAddress;
- }
-
- function _burn(uint256 tokenId) internal override {
- delete cidToMinted[_tokenCIDs[tokenId]];
- delete tokenIdToCreatorPaymentAddress[tokenId];
- delete _tokenCIDs[tokenId];
- unchecked {
- burnCounter++;
- }
- super._burn(tokenId);
- }
-
- /**
- * @dev Split into a second function to avoid stack too deep errors
- */
- function _adminAccountRecoveryForPaymentAddresses(
- uint256[] calldata paymentAddressTokenIds,
- address paymentAddressFactory,
- bytes memory paymentAddressCallData,
- uint256 addressLocationInCallData,
- address originalAddress,
- address payable newAddress
- ) private {
- // Call the factory and get the originalPaymentAddress
- address payable originalPaymentAddress = collectionFactory.proxyCallContract().proxyCallAndReturnContractAddress(
- paymentAddressFactory,
- paymentAddressCallData
- );
-
- // Confirm the original address and swap with the new address
- paymentAddressCallData.replaceAtIf(addressLocationInCallData, originalAddress, newAddress);
-
- // Call the factory and get the newPaymentAddress
- address payable newPaymentAddress = collectionFactory.proxyCallContract().proxyCallAndReturnContractAddress(
- paymentAddressFactory,
- paymentAddressCallData
- );
-
- // For each token, confirm the expected payment address and then update to the new one
- for (uint256 i = 0; i < paymentAddressTokenIds.length; i++) {
- uint256 tokenId = paymentAddressTokenIds[i];
- require(
- tokenIdToCreatorPaymentAddress[tokenId] == originalPaymentAddress,
- "CollectionContract: Payment address is not the expected value"
- );
-
- _setTokenCreatorPaymentAddress(tokenId, newPaymentAddress);
- emit PaymentAddressMigrated(tokenId, originalAddress, newAddress, originalPaymentAddress, newPaymentAddress);
- }
- }
-
- function _baseURI() internal view override returns (string memory) {
- if (bytes(baseURI_).length > 0) {
- return baseURI_;
- }
- return "ipfs://";
- }
-}
diff --git a/example/errors/Contract77.sol b/example/errors/Contract77.sol
deleted file mode 100644
index f3ac550..0000000
--- a/example/errors/Contract77.sol
+++ /dev/null
@@ -1,432 +0,0 @@
-// SPDX-License-Identifier: MIT
-// OpenZeppelin Contracts v4.4.1 (token/ERC721/ERC721.sol)
-
-pragma solidity ^0.8.0;
-
-import "./IERC721Upgradeable.sol";
-import "./IERC721ReceiverUpgradeable.sol";
-import "./extensions/IERC721MetadataUpgradeable.sol";
-import "../../utils/AddressUpgradeable.sol";
-import "../../utils/ContextUpgradeable.sol";
-import "../../utils/StringsUpgradeable.sol";
-import "../../utils/introspection/ERC165Upgradeable.sol";
-import "../../proxy/utils/Initializable.sol";
-
-/**
- * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
- * the Metadata extension, but not including the Enumerable extension, which is available separately as
- * {ERC721Enumerable}.
- */
-contract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {
- using AddressUpgradeable for address;
- using StringsUpgradeable for uint256;
-
- // Token name
- string private _name;
-
- // Token symbol
- string private _symbol;
-
- // Mapping from token ID to owner address
- mapping(uint256 => address) private _owners;
-
- // Mapping owner address to token count
- mapping(address => uint256) private _balances;
-
- // Mapping from token ID to approved address
- mapping(uint256 => address) private _tokenApprovals;
-
- // Mapping from owner to operator approvals
- mapping(address => mapping(address => bool)) private _operatorApprovals;
-
- /**
- * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
- */
- function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {
- __Context_init_unchained();
- __ERC165_init_unchained();
- __ERC721_init_unchained(name_, symbol_);
- }
-
- function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {
- _name = name_;
- _symbol = symbol_;
- }
-
- /**
- * @dev See {IERC165-supportsInterface}.
- */
- function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {
- return
- interfaceId == type(IERC721Upgradeable).interfaceId ||
- interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||
- super.supportsInterface(interfaceId);
- }
-
- /**
- * @dev See {IERC721-balanceOf}.
- */
- function balanceOf(address owner) public view virtual override returns (uint256) {
- require(owner != address(0), "ERC721: balance query for the zero address");
- return _balances[owner];
- }
-
- /**
- * @dev See {IERC721-ownerOf}.
- */
- function ownerOf(uint256 tokenId) public view virtual override returns (address) {
- address owner = _owners[tokenId];
- require(owner != address(0), "ERC721: owner query for nonexistent token");
- return owner;
- }
-
- /**
- * @dev See {IERC721Metadata-name}.
- */
- function name() public view virtual override returns (string memory) {
- return _name;
- }
-
- /**
- * @dev See {IERC721Metadata-symbol}.
- */
- function symbol() public view virtual override returns (string memory) {
- return _symbol;
- }
-
- /**
- * @dev See {IERC721Metadata-tokenURI}.
- */
- function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
- require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
-
- string memory baseURI = _baseURI();
- return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
- }
-
- /**
- * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
- * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
- * by default, can be overriden in child contracts.
- */
- function _baseURI() internal view virtual returns (string memory) {
- return "";
- }
-
- /**
- * @dev See {IERC721-approve}.
- */
- function approve(address to, uint256 tokenId) public virtual override {
- address owner = ERC721Upgradeable.ownerOf(tokenId);
- require(to != owner, "ERC721: approval to current owner");
-
- require(
- _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
- "ERC721: approve caller is not owner nor approved for all"
- );
-
- _approve(to, tokenId);
- }
-
- /**
- * @dev See {IERC721-getApproved}.
- */
- function getApproved(uint256 tokenId) public view virtual override returns (address) {
- require(_exists(tokenId), "ERC721: approved query for nonexistent token");
-
- return _tokenApprovals[tokenId];
- }
-
- /**
- * @dev See {IERC721-setApprovalForAll}.
- */
- function setApprovalForAll(address operator, bool approved) public virtual override {
- _setApprovalForAll(_msgSender(), operator, approved);
- }
-
- /**
- * @dev See {IERC721-isApprovedForAll}.
- */
- function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
- return _operatorApprovals[owner][operator];
- }
-
- /**
- * @dev See {IERC721-transferFrom}.
- */
- function transferFrom(
- address from,
- address to,
- uint256 tokenId
- ) public virtual override {
- //solhint-disable-next-line max-line-length
- require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
-
- _transfer(from, to, tokenId);
- }
-
- /**
- * @dev See {IERC721-safeTransferFrom}.
- */
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId
- ) public virtual override {
- safeTransferFrom(from, to, tokenId, "");
- }
-
- /**
- * @dev See {IERC721-safeTransferFrom}.
- */
- function safeTransferFrom(
- address from,
- address to,
- uint256 tokenId,
- bytes memory _data
- ) public virtual override {
- require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: transfer caller is not owner nor approved");
- _safeTransfer(from, to, tokenId, _data);
- }
-
- /**
- * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
- * are aware of the ERC721 protocol to prevent tokens from being forever locked.
- *
- * `_data` is additional data, it has no specified format and it is sent in call to `to`.
- *
- * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
- * implement alternative mechanisms to perform token transfer, such as signature-based.
- *
- * Requirements:
- *
- * - `from` cannot be the zero address.
- * - `to` cannot be the zero address.
- * - `tokenId` token must exist and be owned by `from`.
- * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
- *
- * Emits a {Transfer} event.
- */
- function _safeTransfer(
- address from,
- address to,
- uint256 tokenId,
- bytes memory _data
- ) internal virtual {
- _transfer(from, to, tokenId);
- require(_checkOnERC721Received(from, to, tokenId, _data), "ERC721: transfer to non ERC721Receiver implementer");
- }
-
- /**
- * @dev Returns whether `tokenId` exists.
- *
- * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
- *
- * Tokens start existing when they are minted (`_mint`),
- * and stop existing when they are burned (`_burn`).
- */
- function _exists(uint256 tokenId) internal view virtual returns (bool) {
- return _owners[tokenId] != address(0);
- }
-
- /**
- * @dev Returns whether `spender` is allowed to manage `tokenId`.
- *
- * Requirements:
- *
- * - `tokenId` must exist.
- */
- function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
- require(_exists(tokenId), "ERC721: operator query for nonexistent token");
- address owner = ERC721Upgradeable.ownerOf(tokenId);
- return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, spender));
- }
-
- /**
- * @dev Safely mints `tokenId` and transfers it to `to`.
- *
- * Requirements:
- *
- * - `tokenId` must not exist.
- * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
- *
- * Emits a {Transfer} event.
- */
- function _safeMint(address to, uint256 tokenId) internal virtual {
- _safeMint(to, tokenId, "");
- }
-
- /**
- * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
- * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
- */
- function _safeMint(
- address to,
- uint256 tokenId,
- bytes memory _data
- ) internal virtual {
- _mint(to, tokenId);
- require(
- _checkOnERC721Received(address(0), to, tokenId, _data),
- "ERC721: transfer to non ERC721Receiver implementer"
- );
- }
-
- /**
- * @dev Mints `tokenId` and transfers it to `to`.
- *
- * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
- *
- * Requirements:
- *
- * - `tokenId` must not exist.
- * - `to` cannot be the zero address.
- *
- * Emits a {Transfer} event.
- */
- function _mint(address to, uint256 tokenId) internal virtual {
- require(to != address(0), "ERC721: mint to the zero address");
- require(!_exists(tokenId), "ERC721: token already minted");
-
- _beforeTokenTransfer(address(0), to, tokenId);
-
- _balances[to] += 1;
- _owners[tokenId] = to;
-
- emit Transfer(address(0), to, tokenId);
- }
-
- /**
- * @dev Destroys `tokenId`.
- * The approval is cleared when the token is burned.
- *
- * Requirements:
- *
- * - `tokenId` must exist.
- *
- * Emits a {Transfer} event.
- */
- function _burn(uint256 tokenId) internal virtual {
- address owner = ERC721Upgradeable.ownerOf(tokenId);
-
- _beforeTokenTransfer(owner, address(0), tokenId);
-
- // Clear approvals
- _approve(address(0), tokenId);
-
- _balances[owner] -= 1;
- delete _owners[tokenId];
-
- emit Transfer(owner, address(0), tokenId);
- }
-
- /**
- * @dev Transfers `tokenId` from `from` to `to`.
- * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
- *
- * Requirements:
- *
- * - `to` cannot be the zero address.
- * - `tokenId` token must be owned by `from`.
- *
- * Emits a {Transfer} event.
- */
- function _transfer(
- address from,
- address to,
- uint256 tokenId
- ) internal virtual {
- require(ERC721Upgradeable.ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
- require(to != address(0), "ERC721: transfer to the zero address");
-
- _beforeTokenTransfer(from, to, tokenId);
-
- // Clear approvals from the previous owner
- _approve(address(0), tokenId);
-
- _balances[from] -= 1;
- _balances[to] += 1;
- _owners[tokenId] = to;
-
- emit Transfer(from, to, tokenId);
- }
-
- /**
- * @dev Approve `to` to operate on `tokenId`
- *
- * Emits a {Approval} event.
- */
- function _approve(address to, uint256 tokenId) internal virtual {
- _tokenApprovals[tokenId] = to;
- emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId);
- }
-
- /**
- * @dev Approve `operator` to operate on all of `owner` tokens
- *
- * Emits a {ApprovalForAll} event.
- */
- function _setApprovalForAll(
- address owner,
- address operator,
- bool approved
- ) internal virtual {
- require(owner != operator, "ERC721: approve to caller");
- _operatorApprovals[owner][operator] = approved;
- emit ApprovalForAll(owner, operator, approved);
- }
-
- /**
- * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
- * The call is not executed if the target address is not a contract.
- *
- * @param from address representing the previous owner of the given token ID
- * @param to target address that will receive the tokens
- * @param tokenId uint256 ID of the token to be transferred
- * @param _data bytes optional data to send along with the call
- * @return bool whether the call correctly returned the expected magic value
- */
- function _checkOnERC721Received(
- address from,
- address to,
- uint256 tokenId,
- bytes memory _data
- ) private returns (bool) {
- if (to.isContract()) {
- try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, _data) returns (bytes4 retval) {
- return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;
- } catch (bytes memory reason) {
- if (reason.length == 0) {
- revert("ERC721: transfer to non ERC721Receiver implementer");
- } else {
- assembly {
- revert(add(32, reason), mload(reason))
- }
- }
- }
- } else {
- return true;
- }
- }
-
- /**
- * @dev Hook that is called before any token transfer. This includes minting
- * and burning.
- *
- * Calling conditions:
- *
- * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
- * transferred to `to`.
- * - When `from` is zero, `tokenId` will be minted for `to`.
- * - When `to` is zero, ``from``'s `tokenId` will be burned.
- * - `from` and `to` are never both zero.
- *
- * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
- */
- function _beforeTokenTransfer(
- address from,
- address to,
- uint256 tokenId
- ) internal virtual {}
- uint256[44] private __gap;
-}
diff --git a/example/greedy-airdropper.sol b/example/greedy-airdropper.sol
deleted file mode 100644
index 06db739..0000000
--- a/example/greedy-airdropper.sol
+++ /dev/null
@@ -1,27 +0,0 @@
-pragma solidity ^0.8.0;
-
-interface IBEP20 {
- function approve(address spender, uint256 amount) external returns (bool);
- function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
-}
-
-contract Airdropper {
- mapping (bytes32 => bool) used;
- event Sent(address indexed token, address indexed sender, address indexed recipient, uint256 tokensToTransfer, uint256 nonce);
-
- function validateAndRegisterClaim(address sender, bytes32 h, uint8 v, bytes32 r, bytes32 s) private {
- bytes memory prefix = "\x19Ethereum Signed Message:\n32";
- address signer = ecrecover(keccak256(abi.encodePacked(prefix, h)), v, r, s);
- require(signer == sender && signer != address(0), "invalid claim");
-
- require(!used[h], "re-use detected");
- used[h] = true;
- }
-
- function claimTokensBEP20(address token, address sender, address recipient, uint256 tokensToTransfer, uint256 nonce, uint8 v, bytes32 r, bytes32 s) public {
- bytes32 h = keccak256(abi.encodePacked(token, sender, recipient, tokensToTransfer, nonce));
- validateAndRegisterClaim(sender, h, v, r, s);
- IBEP20(token).transferFrom(sender, recipient, tokensToTransfer);
- emit Sent(token, sender, recipient, tokensToTransfer, nonce);
- }
-}
\ No newline at end of file
diff --git a/example/import_remapping/TestContract.sol b/example/import_remapping/TestContract.sol
deleted file mode 100644
index d97fd79..0000000
--- a/example/import_remapping/TestContract.sol
+++ /dev/null
@@ -1,10 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.0;
-
-import "@openzeppelin/access/Ownable.sol";
-
-contract TestContract {
- constructor(){
-
- }
-}
diff --git a/example/import_remapping/oz/access/Ownable.sol b/example/import_remapping/oz/access/Ownable.sol
deleted file mode 100644
index 9dce918..0000000
--- a/example/import_remapping/oz/access/Ownable.sol
+++ /dev/null
@@ -1,8 +0,0 @@
-// SPDX-License-Identifier: UNLICENSED
-pragma solidity ^0.8.0;
-
-contract Ownable {
- constructor(){
-
- }
-}
diff --git a/example/import_remapping/remappings.txt b/example/import_remapping/remappings.txt
deleted file mode 100644
index 736243e..0000000
--- a/example/import_remapping/remappings.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-@openzeppelin/=oz/
-@earlybird-interfaces/=lib/earlybird-evm-interfaces/src/
-@magicLane-interfaces/=lib/magiclane-evm-interfaces/src/
-ctx:@magicLane-interfaces2/=lib/magiclane-evm-interfaces2/src/
\ No newline at end of file
diff --git a/example/test.sol b/example/test.sol
deleted file mode 100644
index 78e0427..0000000
--- a/example/test.sol
+++ /dev/null
@@ -1,697 +0,0 @@
-// SPDX-License-Identifier: GPL-3.0-only
-pragma solidity 0.8.17;
-
-import "./Base.sol";
-import {IWithdrawer} from "../interface/IWithdrawer.sol";
-import {MinipoolStatus} from "../types/MinipoolStatus.sol";
-import {MultisigManager} from "./MultisigManager.sol";
-import {Oracle} from "./Oracle.sol";
-import {ProtocolDAO} from "./ProtocolDAO.sol";
-import {Staking} from "./Staking.sol";
-import {Storage} from "./Storage.sol";
-import {TokenggAVAX} from "./tokens/TokenggAVAX.sol";
-import {TokenGGP} from "./tokens/TokenGGP.sol";
-import {Vault} from "./Vault.sol";
-
-import {ERC20} from "@rari-capital/solmate/src/mixins/ERC4626.sol";
-import {FixedPointMathLib} from "@rari-capital/solmate/src/utils/FixedPointMathLib.sol";
-import {ReentrancyGuard} from "@rari-capital/solmate/src/utils/ReentrancyGuard.sol";
-import {SafeTransferLib} from "@rari-capital/solmate/src/utils/SafeTransferLib.sol";
-
-/*
- Data Storage Schema
- NodeIDs are 20 bytes so can use Solidity 'address' as storage type for them
- NodeIDs can be added, but never removed. If a nodeID submits another validation request,
- it will overwrite the old one (only allowed for specific statuses).
-
- MinipoolManager.TotalAVAXLiquidStakerAmt = total for all active minipools (Prelaunch/Launched/Staking)
-
- minipool.count = Starts at 0 and counts up by 1 after a node is added.
-
- minipool.index = of nodeID
- minipool.item.nodeID = nodeID used as primary key (NOT the ascii "Node-123..." but the actual 20 bytes)
- minipool.item.status = enum
- minipool.item.duration = requested validation duration in seconds (performed as 14 day cycles)
- minipool.item.delegationFee = node operator specified fee (must be between 0 and 1 ether) 2% is 0.2 ether
- minipool.item.owner = owner address
- minipool.item.multisigAddr = which Rialto multisig is assigned to manage this validation
- minipool.item.avaxNodeOpAmt = avax deposited by node operator (for this cycle)
- minipool.item.avaxNodeOpInitialAmt = avax deposited by node operator for the **first** validation cycle
- minipool.item.avaxLiquidStakerAmt = avax deposited by users and assigned to this nodeID
-
- // Submitted by the Rialto oracle
- minipool.item.txID = transaction id of the AddValidatorTx
- minipool.item.initialStartTime = actual time the **first** validation cycle was started
- minipool.item.startTime = actual time validation was started
- minipool.item.endTime = actual time validation was finished
- minipool.item.avaxTotalRewardAmt = Actual total avax rewards paid by avalanchego to the TSS P-chain addr
- minipool.item.errorCode = bytes32 that encodes an error msg if something went wrong during launch of minipool
-
- // Calculated in recordStakingEnd()
- minipool.item.avaxNodeOpRewardAmt
- minipool.item.avaxLiquidStakerRewardAmt
- minipool.item.ggpSlashAmt = amt of ggp bond that was slashed if necessary (expected reward amt = avaxLiquidStakerAmt * x%/yr / ggpPriceInAvax)
-*/
-
-/// @title Minipool creation and management
-contract MinipoolManager is Base, ReentrancyGuard, IWithdrawer {
- using FixedPointMathLib for uint256;
- using SafeTransferLib for address;
- using SafeTransferLib for ERC20;
-
- error InsufficientGGPCollateralization();
- error InsufficientAVAXForMinipoolCreation();
- error InvalidAmount();
- error InvalidAVAXAssignmentRequest();
- error InvalidStartTime();
- error InvalidEndTime();
- error InvalidMultisigAddress();
- error InvalidNodeID();
- error InvalidStateTransition();
- error MinipoolNotFound();
- error OnlyOwner();
- error CancellationTooEarly();
-
- event GGPSlashed(address indexed nodeID, uint256 ggp);
- event MinipoolStatusChanged(address indexed nodeID, MinipoolStatus indexed status);
-
- ERC20 public immutable ggp;
- TokenggAVAX public immutable ggAVAX;
-
- /// @dev Not used for storage, just for returning data from view functions
- struct Minipool {
- int256 index;
- address nodeID;
- uint256 status;
- uint256 duration;
- uint256 delegationFee;
- address owner;
- address multisigAddr;
- uint256 avaxNodeOpAmt;
- uint256 avaxNodeOpInitialAmt;
- uint256 avaxLiquidStakerAmt;
- // Submitted by the Rialto Oracle
- bytes32 txID;
- uint256 initialStartTime;
- uint256 startTime;
- uint256 endTime;
- uint256 avaxTotalRewardAmt;
- bytes32 errorCode;
- // Calculated in recordStakingEnd
- uint256 ggpSlashAmt;
- uint256 avaxNodeOpRewardAmt;
- uint256 avaxLiquidStakerRewardAmt;
- }
-
- function receiveWithdrawalAVAX() external payable {}
-
- //
- // GUARDS
- //
-
- /// @notice Look up minipool owner by minipool index
- /// @param minipoolIndex A valid minipool index
- /// @return minipool owner or revert
- function onlyOwner(int256 minipoolIndex) private view returns (address) {
- address owner = getAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".owner")));
- if (msg.sender != owner) {
- revert OnlyOwner();
- }
- return owner;
- }
-
- /// @notice Verifies the multisig trying to use the given node ID is valid
- /// @dev Look up multisig index by minipool nodeID
- /// @param nodeID 20-byte Avalanche node ID
- /// @return minipool index or revert
- function onlyValidMultisig(address nodeID) private view returns (int256) {
- int256 minipoolIndex = requireValidMinipool(nodeID);
-
- address assignedMultisig = getAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".multisigAddr")));
- if (msg.sender != assignedMultisig) {
- revert InvalidMultisigAddress();
- }
- return minipoolIndex;
- }
-
- /// @notice Look up minipool index by minipool nodeID
- /// @param nodeID 20-byte Avalanche node ID
- /// @return minipool index or revert
- function requireValidMinipool(address nodeID) private view returns (int256) {
- int256 minipoolIndex = getIndexOf(nodeID);
- if (minipoolIndex == -1) {
- revert MinipoolNotFound();
- }
-
- return minipoolIndex;
- }
-
- /// @notice Ensure a minipool is allowed to move to the "to" state
- /// @param minipoolIndex A valid minipool index
- /// @param to New status
- function requireValidStateTransition(int256 minipoolIndex, MinipoolStatus to) private view {
- bytes32 statusKey = keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status"));
- MinipoolStatus currentStatus = MinipoolStatus(getUint(statusKey));
- bool isValid;
-
- if (currentStatus == MinipoolStatus.Prelaunch) {
- isValid = (to == MinipoolStatus.Launched || to == MinipoolStatus.Canceled);
- } else if (currentStatus == MinipoolStatus.Launched) {
- isValid = (to == MinipoolStatus.Staking || to == MinipoolStatus.Error);
- } else if (currentStatus == MinipoolStatus.Staking) {
- isValid = (to == MinipoolStatus.Withdrawable || to == MinipoolStatus.Error);
- } else if (currentStatus == MinipoolStatus.Withdrawable || currentStatus == MinipoolStatus.Error) {
- isValid = (to == MinipoolStatus.Finished || to == MinipoolStatus.Prelaunch);
- } else if (currentStatus == MinipoolStatus.Finished || currentStatus == MinipoolStatus.Canceled) {
- // Once a node is finished/canceled, if they re-validate they go back to beginning state
- isValid = (to == MinipoolStatus.Prelaunch);
- } else {
- isValid = false;
- }
-
- if (!isValid) {
- revert InvalidStateTransition();
- }
- }
-
- constructor(
- Storage storageAddress,
- ERC20 ggp_,
- TokenggAVAX ggAVAX_
- ) Base(storageAddress) {
- version = 1;
- ggp = ggp_;
- ggAVAX = ggAVAX_;
- }
-
- //
- // OWNER FUNCTIONS
- //
-
- /// @notice Accept AVAX deposit from node operator to create a Minipool. Node Operator must be staking GGP. Open to public.
- /// @param nodeID 20-byte Avalanche node ID
- /// @param duration Requested validation period in seconds
- /// @param delegationFee Percentage delegation fee in units of ether (2% is 0.2 ether)
- /// @param avaxAssignmentRequest Amount of requested AVAX to be matched for this Minipool
- function createMinipool(
- address nodeID,
- uint256 duration,
- uint256 delegationFee,
- uint256 avaxAssignmentRequest
- ) external payable whenNotPaused {
- if (nodeID == address(0)) {
- revert InvalidNodeID();
- }
-
- ProtocolDAO dao = ProtocolDAO(getContractAddress("ProtocolDAO"));
- if (
- // Current rule is matched funds must be 1:1 nodeOp:LiqStaker
- msg.value != avaxAssignmentRequest ||
- avaxAssignmentRequest > dao.getMinipoolMaxAVAXAssignment() ||
- avaxAssignmentRequest < dao.getMinipoolMinAVAXAssignment()
- ) {
- revert InvalidAVAXAssignmentRequest();
- }
-
- if (msg.value + avaxAssignmentRequest < dao.getMinipoolMinAVAXStakingAmt()) {
- revert InsufficientAVAXForMinipoolCreation();
- }
-
- Staking staking = Staking(getContractAddress("Staking"));
- staking.increaseMinipoolCount(msg.sender);
- staking.increaseAVAXStake(msg.sender, msg.value);
- staking.increaseAVAXAssigned(msg.sender, avaxAssignmentRequest);
-
- if (staking.getRewardsStartTime(msg.sender) == 0) {
- staking.setRewardsStartTime(msg.sender, block.timestamp);
- }
-
- uint256 ratio = staking.getCollateralizationRatio(msg.sender);
- if (ratio < dao.getMinCollateralizationRatio()) {
- revert InsufficientGGPCollateralization();
- }
-
- // Get a Rialto multisig to assign for this minipool
- MultisigManager multisigManager = MultisigManager(getContractAddress("MultisigManager"));
- address multisig = multisigManager.requireNextActiveMultisig();
-
- // Create or update a minipool record for nodeID
- // If nodeID exists, only allow overwriting if node is finished or canceled
- // (completed its validation period and all rewards paid and processing is complete)
- int256 minipoolIndex = getIndexOf(nodeID);
- if (minipoolIndex != -1) {
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Prelaunch);
- resetMinipoolData(minipoolIndex);
- // Also reset initialStartTime as we are starting a whole new validation
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".initialStartTime")), 0);
- } else {
- minipoolIndex = int256(getUint(keccak256("minipool.count")));
- // The minipoolIndex is stored 1 greater than actual value. The 1 is subtracted in getIndexOf()
- setUint(keccak256(abi.encodePacked("minipool.index", nodeID)), uint256(minipoolIndex + 1));
- setAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".nodeID")), nodeID);
- addUint(keccak256("minipool.count"), 1);
- }
-
- // Save the attrs individually in the k/v store
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Prelaunch));
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".duration")), duration);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".delegationFee")), delegationFee);
- setAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".owner")), msg.sender);
- setAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".multisigAddr")), multisig);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpInitialAmt")), msg.value);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpAmt")), msg.value);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")), avaxAssignmentRequest);
-
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Prelaunch);
-
- Vault vault = Vault(getContractAddress("Vault"));
- vault.depositAVAX{value: msg.value}();
- }
-
- /// @notice Owner of a minipool can cancel the (prelaunch) minipool
- /// @param nodeID 20-byte Avalanche node ID the Owner registered with
- function cancelMinipool(address nodeID) external nonReentrant {
- Staking staking = Staking(getContractAddress("Staking"));
- ProtocolDAO dao = ProtocolDAO(getContractAddress("ProtocolDAO"));
- int256 index = requireValidMinipool(nodeID);
- onlyOwner(index);
- // make sure they meet the wait period requirement
- if (block.timestamp - staking.getRewardsStartTime(msg.sender) < dao.getMinipoolCancelMoratoriumSeconds()) {
- revert CancellationTooEarly();
- }
- _cancelMinipoolAndReturnFunds(nodeID, index);
- }
-
- /// @notice Withdraw function for a Node Operator to claim all AVAX funds they are due (original AVAX staked, plus any AVAX rewards)
- /// @param nodeID 20-byte Avalanche node ID the Node Operator registered with
- function withdrawMinipoolFunds(address nodeID) external nonReentrant {
- int256 minipoolIndex = requireValidMinipool(nodeID);
- address owner = onlyOwner(minipoolIndex);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Finished);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Finished));
-
- uint256 avaxNodeOpAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpAmt")));
- uint256 avaxNodeOpRewardAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpRewardAmt")));
- uint256 totalAvaxAmt = avaxNodeOpAmt + avaxNodeOpRewardAmt;
-
- Staking staking = Staking(getContractAddress("Staking"));
- staking.decreaseAVAXStake(owner, avaxNodeOpAmt);
-
- Vault vault = Vault(getContractAddress("Vault"));
- vault.withdrawAVAX(totalAvaxAmt);
- owner.safeTransferETH(totalAvaxAmt);
- }
-
- //
- // RIALTO FUNCTIONS
- //
-
- /// @notice Verifies that the minipool related the the given node ID is able to a validator
- /// @dev Rialto calls this to see if a claim would succeed. Does not change state.
- /// @param nodeID 20-byte Avalanche node ID
- /// @return boolean representing if the minipool can become a validator
- function canClaimAndInitiateStaking(address nodeID) external view returns (bool) {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Launched);
-
- uint256 avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")));
- return avaxLiquidStakerAmt <= ggAVAX.amountAvailableForStaking();
- }
-
- /// @notice Removes the AVAX associated with a minipool from the protocol to stake it on Avalanche and register the node as a validator
- /// @param nodeID 20-byte Avalanche node ID
- /// @dev Rialto calls this to initiate registering a minipool for staking and validation of the P-chain.
- function claimAndInitiateStaking(address nodeID) external {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Launched);
-
- uint256 avaxNodeOpAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpAmt")));
- uint256 avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")));
-
- // Transfer funds to this contract and then send to multisig
- ggAVAX.withdrawForStaking(avaxLiquidStakerAmt);
- addUint(keccak256("MinipoolManager.TotalAVAXLiquidStakerAmt"), avaxLiquidStakerAmt);
-
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Launched));
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Launched);
-
- Vault vault = Vault(getContractAddress("Vault"));
- vault.withdrawAVAX(avaxNodeOpAmt);
-
- uint256 totalAvaxAmt = avaxNodeOpAmt + avaxLiquidStakerAmt;
- msg.sender.safeTransferETH(totalAvaxAmt);
- }
-
- /// @notice Rialto calls this after successfully registering the minipool as a validator for Avalanche
- /// @param nodeID 20-byte Avalanche node ID
- /// @param txID The ID of the transaction that successfully registered the node with Avalanche to become a validater
- /// @param startTime Time the node became a validator
- function recordStakingStart(
- address nodeID,
- bytes32 txID,
- uint256 startTime
- ) external {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Staking);
- if (startTime > block.timestamp) {
- revert InvalidStartTime();
- }
-
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Staking));
- setBytes32(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".txID")), txID);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".startTime")), startTime);
-
- // If this is the first of many cycles, set the initialStartTime
- uint256 initialStartTime = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".initialStartTime")));
- if (initialStartTime == 0) {
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".initialStartTime")), startTime);
- }
-
- address owner = getAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".owner")));
- uint256 avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")));
- Staking staking = Staking(getContractAddress("Staking"));
- if (staking.getAVAXAssignedHighWater(owner) < staking.getAVAXAssigned(owner)) {
- staking.increaseAVAXAssignedHighWater(owner, avaxLiquidStakerAmt);
- }
-
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Staking);
- }
-
- /// @notice Records the nodeID's validation period end
- /// @param nodeID 20-byte Avalanche node ID
- /// @param endTime The time the node ID stopped validating Avalanche
- /// @param avaxTotalRewardAmt The rewards the node recieved from Avalanche for being a validator
- /// @dev Rialto will xfer back all staked avax + avax rewards. Also handles the slashing of node ops GGP bond.
- function recordStakingEnd(
- address nodeID,
- uint256 endTime,
- uint256 avaxTotalRewardAmt
- ) external payable {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Withdrawable);
-
- uint256 startTime = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".startTime")));
- if (endTime <= startTime || endTime > block.timestamp) {
- revert InvalidEndTime();
- }
-
- uint256 avaxNodeOpAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpAmt")));
- uint256 avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")));
- uint256 totalAvaxAmt = avaxNodeOpAmt + avaxLiquidStakerAmt;
- if (msg.value != totalAvaxAmt + avaxTotalRewardAmt) {
- revert InvalidAmount();
- }
-
- address owner = getAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".owner")));
-
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Withdrawable));
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".endTime")), endTime);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxTotalRewardAmt")), avaxTotalRewardAmt);
-
- // Calculate rewards splits (these will all be zero if no rewards were recvd)
- // TODO Revisit this logic if we ever allow unequal matched funds
- uint256 avaxHalfRewards = avaxTotalRewardAmt / 2;
-
- // Node operators recv an additional commission fee
- ProtocolDAO dao = ProtocolDAO(getContractAddress("ProtocolDAO"));
- uint256 avaxLiquidStakerRewardAmt = avaxHalfRewards - avaxHalfRewards.mulWadDown(dao.getMinipoolNodeCommissionFeePct());
- uint256 avaxNodeOpRewardAmt = avaxTotalRewardAmt - avaxLiquidStakerRewardAmt;
-
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpRewardAmt")), avaxNodeOpRewardAmt);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerRewardAmt")), avaxLiquidStakerRewardAmt);
-
- // No rewards means validation period failed, must slash node ops GGP.
- if (avaxTotalRewardAmt == 0) {
- slash(minipoolIndex);
- }
-
- // Send the nodeOps AVAX + rewards to vault so they can claim later
- Vault vault = Vault(getContractAddress("Vault"));
- vault.depositAVAX{value: avaxNodeOpAmt + avaxNodeOpRewardAmt}();
- // Return Liq stakers funds + rewards
- ggAVAX.depositFromStaking{value: avaxLiquidStakerAmt + avaxLiquidStakerRewardAmt}(avaxLiquidStakerAmt, avaxLiquidStakerRewardAmt);
- subUint(keccak256("MinipoolManager.TotalAVAXLiquidStakerAmt"), avaxLiquidStakerAmt);
-
- Staking staking = Staking(getContractAddress("Staking"));
- staking.decreaseAVAXAssigned(owner, avaxLiquidStakerAmt);
- staking.decreaseMinipoolCount(owner);
-
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Withdrawable);
- }
-
- /// @notice Re-stake a minipool, compounding all rewards recvd
- /// @param nodeID 20-byte Avalanche node ID
- function recreateMinipool(address nodeID) external whenNotPaused {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Prelaunch);
- Minipool memory mp = getMinipool(minipoolIndex);
- // Compound the avax plus rewards
- // NOTE Assumes a 1:1 nodeOp:liqStaker funds ratio
- uint256 compoundedAvaxNodeOpAmt = mp.avaxNodeOpAmt + mp.avaxNodeOpRewardAmt;
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpAmt")), compoundedAvaxNodeOpAmt);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")), compoundedAvaxNodeOpAmt);
-
- Staking staking = Staking(getContractAddress("Staking"));
- // Only increase AVAX stake by rewards amount we are compounding
- // since AVAX stake is only decreased by withdrawMinipool()
- staking.increaseAVAXStake(mp.owner, mp.avaxNodeOpRewardAmt);
- staking.increaseAVAXAssigned(mp.owner, compoundedAvaxNodeOpAmt);
- staking.increaseMinipoolCount(mp.owner);
-
- if (staking.getRewardsStartTime(mp.owner) == 0) {
- // Edge case where calculateAndDistributeRewards has reset their rewards time even though they are still cycling
- // So we re-set it here to their initial start time for this minipool
- staking.setRewardsStartTime(mp.owner, mp.initialStartTime);
- }
-
- ProtocolDAO dao = ProtocolDAO(getContractAddress("ProtocolDAO"));
- uint256 ratio = staking.getCollateralizationRatio(mp.owner);
- if (ratio < dao.getMinCollateralizationRatio()) {
- revert InsufficientGGPCollateralization();
- }
-
- resetMinipoolData(minipoolIndex);
-
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Prelaunch));
-
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Prelaunch);
- }
-
- /// @notice A staking error occured while registering the node as a validator
- /// @param nodeID 20-byte Avalanche node ID
- /// @param errorCode The code that represents the reason for failure
- /// @dev Rialto was unable to start the validation period, so cancel and refund all money
- function recordStakingError(address nodeID, bytes32 errorCode) external payable {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Error);
-
- address owner = getAddress(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".owner")));
- uint256 avaxNodeOpAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpAmt")));
- uint256 avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerAmt")));
-
- if (msg.value != (avaxNodeOpAmt + avaxLiquidStakerAmt)) {
- revert InvalidAmount();
- }
-
- setBytes32(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".errorCode")), errorCode);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Error));
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxTotalRewardAmt")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxNodeOpRewardAmt")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".avaxLiquidStakerRewardAmt")), 0);
-
- // Send the nodeOps AVAX to vault so they can claim later
- Vault vault = Vault(getContractAddress("Vault"));
- vault.depositAVAX{value: avaxNodeOpAmt}();
-
- // Return Liq stakers funds
- ggAVAX.depositFromStaking{value: avaxLiquidStakerAmt}(avaxLiquidStakerAmt, 0);
-
- Staking staking = Staking(getContractAddress("Staking"));
- staking.decreaseAVAXAssigned(owner, avaxLiquidStakerAmt);
-
- subUint(keccak256("MinipoolManager.TotalAVAXLiquidStakerAmt"), avaxLiquidStakerAmt);
-
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Error);
- }
-
- /// @notice Multisig can cancel a minipool if a problem was encountered *before* claimAndInitiateStaking() was called
- /// @param nodeID 20-byte Avalanche node ID
- /// @param errorCode The code that represents the reason for failure
- function cancelMinipoolByMultisig(address nodeID, bytes32 errorCode) external {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- setBytes32(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".errorCode")), errorCode);
- _cancelMinipoolAndReturnFunds(nodeID, minipoolIndex);
- }
-
- /// @notice Multisig can move a minipool from the error state to the finished state, after a human review of the error
- /// @param nodeID 20-byte Avalanche node ID
- function finishFailedMinipoolByMultisig(address nodeID) external {
- int256 minipoolIndex = onlyValidMultisig(nodeID);
- requireValidStateTransition(minipoolIndex, MinipoolStatus.Finished);
- setUint(keccak256(abi.encodePacked("minipool.item", minipoolIndex, ".status")), uint256(MinipoolStatus.Finished));
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Finished);
- }
-
- //
- // VIEW FUNCTIONS
- //
-
- /// @notice Get the total amount of AVAX from liquid stakers that is being used for minipools
- /// @dev Get the total AVAX *actually* withdrawn from ggAVAX and sent to Rialto
- function getTotalAVAXLiquidStakerAmt() public view returns (uint256) {
- return getUint(keccak256("MinipoolManager.TotalAVAXLiquidStakerAmt"));
- }
-
- /// @notice Calculates how much GGP should be slashed given an expected avaxRewardAmt
- /// @param avaxRewardAmt The amount of AVAX that should have been awarded to the validator by Avalanche
- function calculateGGPSlashAmt(uint256 avaxRewardAmt) public view returns (uint256) {
- Oracle oracle = Oracle(getContractAddress("Oracle"));
- (uint256 ggpPriceInAvax, ) = oracle.getGGPPriceInAVAX();
- return avaxRewardAmt.divWadDown(ggpPriceInAvax);
- }
-
- /// @notice Given a duration and an AVAX amt, calculate how much AVAX should be earned via validation rewards
- /// @param duration The length of validation in seconds
- /// @param avaxAmt The amount of AVAX the node staked for their validation period
- /// @return The approximate rewards the node should recieve from Avalanche for beign a validator
- function getExpectedAVAXRewardsAmt(uint256 duration, uint256 avaxAmt) public view returns (uint256) {
- ProtocolDAO dao = ProtocolDAO(getContractAddress("ProtocolDAO"));
- uint256 rate = dao.getExpectedAVAXRewardsRate();
- return (avaxAmt.mulWadDown(rate) * duration) / 365 days;
- }
-
- /// @notice The index of a minipool. Returns -1 if the minipool is not found
- /// @param nodeID 20-byte Avalanche node ID
- /// @return The index for the given minipool
- function getIndexOf(address nodeID) public view returns (int256) {
- return int256(getUint(keccak256(abi.encodePacked("minipool.index", nodeID)))) - 1;
- }
-
- /// @notice Gets the minipool information from the node ID
- /// @param nodeID 20-byte Avalanche node ID
- function getMinipoolByNodeID(address nodeID) public view returns (Minipool memory mp) {
- int256 index = getIndexOf(nodeID);
- return getMinipool(index);
- }
-
- /// @notice Gets the minipool information using the minipool's index
- /// @param index Index of the minipool
- /// @return mp struct containing the minipool's properties
- function getMinipool(int256 index) public view returns (Minipool memory mp) {
- mp.index = index;
- mp.nodeID = getAddress(keccak256(abi.encodePacked("minipool.item", index, ".nodeID")));
- mp.status = getUint(keccak256(abi.encodePacked("minipool.item", index, ".status")));
- mp.duration = getUint(keccak256(abi.encodePacked("minipool.item", index, ".duration")));
- mp.delegationFee = getUint(keccak256(abi.encodePacked("minipool.item", index, ".delegationFee")));
- mp.owner = getAddress(keccak256(abi.encodePacked("minipool.item", index, ".owner")));
- mp.multisigAddr = getAddress(keccak256(abi.encodePacked("minipool.item", index, ".multisigAddr")));
- mp.avaxNodeOpAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxNodeOpAmt")));
- mp.avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxLiquidStakerAmt")));
- mp.txID = getBytes32(keccak256(abi.encodePacked("minipool.item", index, ".txID")));
- mp.initialStartTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".initialStartTime")));
- mp.startTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".startTime")));
- mp.endTime = getUint(keccak256(abi.encodePacked("minipool.item", index, ".endTime")));
- mp.avaxTotalRewardAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxTotalRewardAmt")));
- mp.errorCode = getBytes32(keccak256(abi.encodePacked("minipool.item", index, ".errorCode")));
- mp.avaxNodeOpInitialAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxNodeOpInitialAmt")));
- mp.avaxNodeOpRewardAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxNodeOpRewardAmt")));
- mp.avaxLiquidStakerRewardAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxLiquidStakerRewardAmt")));
- mp.ggpSlashAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".ggpSlashAmt")));
- }
-
- /// @notice Get minipools in a certain status (limit=0 means no pagination)
- /// @param status The MinipoolStatus to be used as a filter
- /// @param offset The number the result should be offset by
- /// @param limit The limit to the amount of minipools that should be returned
- /// @return minipools in the protocol that adhear to the paramaters
- function getMinipools(
- MinipoolStatus status,
- uint256 offset,
- uint256 limit
- ) public view returns (Minipool[] memory minipools) {
- uint256 totalMinipools = getUint(keccak256("minipool.count"));
- uint256 max = offset + limit;
- if (max > totalMinipools || limit == 0) {
- max = totalMinipools;
- }
- minipools = new Minipool[](max - offset);
- uint256 total = 0;
- for (uint256 i = offset; i < max; i++) {
- Minipool memory mp = getMinipool(int256(i));
- if (mp.status == uint256(status)) {
- minipools[total] = mp;
- total++;
- }
- }
- // Dirty hack to cut unused elements off end of return value (from RP)
- // solhint-disable-next-line no-inline-assembly
- assembly {
- mstore(minipools, total)
- }
- }
-
- /// @notice The total count of minipools in the protocol
- function getMinipoolCount() public view returns (uint256) {
- return getUint(keccak256("minipool.count"));
- }
-
- //
- // PRIVATE FUNCTIONS
- //
-
- /// @notice Cancels the minipool and returns the funds related to it
- /// @dev At this point we dont have any liq staker funds withdrawn from ggAVAX so no need to return them
- /// @param nodeID 20-byte Avalanche node ID
- /// @param index Index of the minipool
- function _cancelMinipoolAndReturnFunds(address nodeID, int256 index) private {
- requireValidStateTransition(index, MinipoolStatus.Canceled);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".status")), uint256(MinipoolStatus.Canceled));
-
- address owner = getAddress(keccak256(abi.encodePacked("minipool.item", index, ".owner")));
- uint256 avaxNodeOpAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxNodeOpAmt")));
- uint256 avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxLiquidStakerAmt")));
-
- Staking staking = Staking(getContractAddress("Staking"));
- staking.decreaseAVAXStake(owner, avaxNodeOpAmt);
- staking.decreaseAVAXAssigned(owner, avaxLiquidStakerAmt);
-
- staking.decreaseMinipoolCount(owner);
-
- emit MinipoolStatusChanged(nodeID, MinipoolStatus.Canceled);
-
- Vault vault = Vault(getContractAddress("Vault"));
- vault.withdrawAVAX(avaxNodeOpAmt);
- owner.safeTransferETH(avaxNodeOpAmt);
- }
-
- /// @notice Slashes the GPP of the minipool with the given index
- /// @dev Extracted this because of "stack too deep" errors.
- /// @param index Index of the minipool
- function slash(int256 index) private {
- address nodeID = getAddress(keccak256(abi.encodePacked("minipool.item", index, ".nodeID")));
- address owner = getAddress(keccak256(abi.encodePacked("minipool.item", index, ".owner")));
- uint256 duration = getUint(keccak256(abi.encodePacked("minipool.item", index, ".duration")));
- uint256 avaxLiquidStakerAmt = getUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxLiquidStakerAmt")));
- uint256 expectedAVAXRewardsAmt = getExpectedAVAXRewardsAmt(duration, avaxLiquidStakerAmt);
- uint256 slashGGPAmt = calculateGGPSlashAmt(expectedAVAXRewardsAmt);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".ggpSlashAmt")), slashGGPAmt);
-
- emit GGPSlashed(nodeID, slashGGPAmt);
-
- Staking staking = Staking(getContractAddress("Staking"));
- staking.slashGGP(owner, slashGGPAmt);
- }
-
- /// @notice Reset all the data for a given minipool (for a previous validation cycle, so do not reset initial amounts)
- /// @param index Index of the minipool
- function resetMinipoolData(int256 index) private {
- setBytes32(keccak256(abi.encodePacked("minipool.item", index, ".txID")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".startTime")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".endTime")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxTotalRewardAmt")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxNodeOpRewardAmt")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".avaxLiquidStakerRewardAmt")), 0);
- setUint(keccak256(abi.encodePacked("minipool.item", index, ".ggpSlashAmt")), 0);
- setBytes32(keccak256(abi.encodePacked("minipool.item", index, ".errorCode")), 0);
- }
-}
\ No newline at end of file
diff --git a/main.py b/main.py
deleted file mode 100644
index e6f8353..0000000
--- a/main.py
+++ /dev/null
@@ -1,500 +0,0 @@
-import traceback
-
-from antlr4 import InputStream, CommonTokenStream
-
-from solidity_parser.grammar.v060.SolidityLexer import SolidityLexer as SolidityLexer060
-from solidity_parser.grammar.v060.SolidityParser import SolidityParser as SolidityParser060
-
-
-from solidity_parser.grammar.v070.SolidityLexer import SolidityLexer as SolidityLexer070
-from solidity_parser.grammar.v070.SolidityParser import SolidityParser as SolidityParser070
-
-from solidity_parser.grammar.v080.SolidityLexer import SolidityLexer as SolidityLexer080
-from solidity_parser.grammar.v080.SolidityParser import SolidityParser as SolidityParser080
-
-from solidity_parser.grammar.v088.SolidityLexer import SolidityLexer as SolidityLexer088
-from solidity_parser.grammar.v088.SolidityParser import SolidityParser as SolidityParser088
-
-from solidity_parser.collectors.collector import get_minor_ver
-# from solidity_parser.ast.nodes import Contract, ContractType
-import prettyprinter as pp
-
-from solidity_parser.ast.parsers.parsers060 import Parser060
-from solidity_parser.ast.parsers.parsers070 import Parser070
-from solidity_parser.ast.parsers.parsers080 import Parser080
-from solidity_parser.ast.parsers.parsers088 import Parser088
-
-from solidity_parser.ast import solnodes, solnodes2
-from solidity_parser.ast import symtab
-
-import os
-import json
-import sys
-
-from solidity_parser.filesys import VirtualFileSystem
-from solidity_parser.ast.helper import make_ast
-
-import solidity_parser.errors as errors
-
-from solidity_parser.util import version_util
-
-def fname(node):
- # id = node.functionDescriptor().identifier()
- id = node.identifier()
- if id is not None:
- return id.Identifier().getText(), False
- else:
- return '<' + node.functionDescriptor().getText() + '>', True
-
-
-# def visit(node, parent=None):
-# if isinstance(node, SolidityParser.FunctionDefinitionContext):
-# name, special = fname(node)
-# if not special:
-# print(name)
-# code = node.block()
-# if code is not None:
-# p = Parser080()
-# ast = p.make(code)
-# pp.pprint(ast)
-# elif not isinstance(node, TerminalNode):
-# for c in node.children:
-# visit(c, node)
-
-
-def get_contracts_from_descriptors(input_files):
- for file_name in input_files:
- with open(file_name, encoding='utf-8') as file:
- descriptors = json.load(file)
- if len(descriptors) != 1:
- raise Exception("piss")
- # print(json.dumps(d, sort_keys=True, indent=2))
- # print(file_name)
- source_codes_str = descriptors[0]['SourceCode']
-
- if source_codes_str[0] == '{' and source_codes_str[1] == '{' and source_codes_str[-1] == '}' and \
- source_codes_str[-2] == '}':
- # some weird descriptor object with {{ sources: { "a.sol", {content: "src" }, ... } ... }}
- source_codes_str_inner = source_codes_str[1:-1]
- descriptors2 = json.loads(source_codes_str_inner)
-
- source_codes = [content_desc['content'] for (name, content_desc) in descriptors2['sources'].items()]
- else:
- # source_code_str is either the source code of the contract or a json
- # object containing source codes for the contracts...
- try:
- source_codes = json.loads(source_codes_str)
- except json.decoder.JSONDecodeError:
- source_codes = [source_codes_str]
-
- for sc in source_codes:
- minor_vers = get_minor_ver(sc)
- if minor_vers is not None:
- yield file_name, minor_vers, sc
-
-
-def try_parse_contract(file_name, version, contract_source, idx):
- contract_input = InputStream(contract_source)
-
- if version < 7:
- grammar_parser_type = SolidityParser060
- grammar_lexer_type = SolidityLexer060
- ast_parser = Parser060()
- elif 8 > version >= 7:
- grammar_parser_type = SolidityParser070
- grammar_lexer_type = SolidityLexer070
- ast_parser = Parser070()
- elif version >= 8:
- grammar_parser_type = SolidityParser080
- grammar_lexer_type = SolidityLexer080
- ast_parser = Parser080()
- else:
- raise KeyError(f"dingle error, v{version}")
-
- lexer = grammar_lexer_type(contract_input)
- stream = CommonTokenStream(lexer)
- parser = grammar_parser_type(stream)
-
- try:
- tree = parser.sourceUnit()
- source_units = tree.children
-
- for su in source_units:
- u = ast_parser.make(su)
- # pp.pprint(u)
- print(f"pass, idx:{idx}")
- except Exception as e:
- print(f"piss: {file_name} {version} idx={idx}")
- print(contract_source)
- if idx is not None:
- with open(f"../example/errors/Contract{idx}.sol", "w", encoding='utf-8') as text_file:
- text_file.write(contract_source)
- raise e
-
-
-def get_ast(file_path):
- return make_ast(open(file_path, 'r').read())
-
-
-def type_of(node):
- if isinstance(node, solnodes.GetMember):
- if isinstance(node.obj_base, solnodes.Ident):
- print(node)
- print(node.scope.find(node.obj_base.text))
-def dfs(node):
- for (key,val) in vars(node).items():
-
- if isinstance(val, solnodes.GetMember):
- type_of(val)
-
- # if isinstance(val, solnodes.Ident):
- # if not hasattr(val, 'location'):
- # print(f"{val} has no location")
- # elif not val.scope.find(str(val)):
- # print(f"{val.scope.find_first_ancestor(lambda x: isinstance(x, symtab.FileScope)).get_names()} {val} @ {val.location} => {val.scope.find(str(val)) is not None}")
-
- if isinstance(val, solnodes.Node):
- dfs(val)
- elif isinstance(val, list):
- for x in val:
- dfs(x)
-
-
-import logging
-from solidity_parser.ast.ast2builder import Builder as Builder2
-from glob import glob
-import re
-import solidity_parser.ast.helper as asthelper
-from solidity_parser.collectors import collector
-
-version_pattern = pattern = re.compile(r"v(\d)\.(\d)\.[0-9]+", re.IGNORECASE)
-
-if __name__ == '__main__':
- pp.install_extras()
- logging.basicConfig( level=logging.CRITICAL)
-
- base_dir = 'F:/downloads/Contracts/00/00'
- all_files = [os.path.join(dp, f) for dp, dn, filenames in os.walk(base_dir) for f in filenames]
-
- # file_name = 'F:/downloads/Contracts/00/00/000000000000c1cb11d5c062901f32d06248ce48'
-
- # start_idx = 182
- start_idx = 35
- idx = 0
-
- for file_name in all_files:
- if idx < start_idx:
- idx += 1
- continue
-
- try:
- with open(file_name, encoding='utf-8') as file:
- descriptors = json.load(file)
- assert isinstance(descriptors, list)
- assert len(descriptors) == 1
- desc = descriptors[0]
-
- vfs = VirtualFileSystem(base_path='',
- # cwd=cwd,
- include_paths=[])
-
- symtab_builder = symtab.Builder2(vfs)
-
- file_scopes = []
-
- try:
- def creator(input_src, *args, **kwargs):
- try:
- v = version_util.extract_version_from_src_input(input_src)
- except:
- v = version_util.parse_version(desc['CompilerVersion'])
- nodes = asthelper.make_ast(input_src, *args, **kwargs, version=v)
- for n in nodes:
- if n:
- n.ver = v
- return nodes
-
- if desc['SourceCode'].startswith('{{') and desc['SourceCode'].endswith('}}'):
- source_contents = {}
-
-
- def _read_file_callback(su_name, base_dir, include_paths) -> str:
- return su_name, source_contents[su_name]
-
- # required shims
- vfs._read_file_callback = _read_file_callback
-
- add_loaded_source_original = vfs._add_loaded_source
- def _add_loaded_source(*args, **kwargs):
- return add_loaded_source_original(*args, **kwargs, creator=creator)
- vfs._add_loaded_source = _add_loaded_source
-
- srcs = json.loads(desc['SourceCode'][1:-1])['sources']
- for c_name, vv in srcs.items():
- c_code = vv['content']
- source_contents[c_name] = c_code
-
- for f in source_contents.keys():
- fs = symtab_builder.process_or_find_from_base_dir(f)
- file_scopes.append(fs)
- else:
- c_name = desc['ContractName'] + '.sol'
- c_code = desc['SourceCode']
- loaded_source = vfs._add_loaded_source(c_name, c_code, creator, c_name)
- file_scope = symtab_builder.process_or_find(loaded_source)
- file_scopes.append(file_scope)
- except errors.AntlrParsingError as e:
- # i.e. malformed syntax inputs
- print(f"ast1 parsing error idx={idx}", file=sys.stderr)
- traceback.print_exc()
- continue
-
- ast2_builder = Builder2()
- ast2_builder.enqueue_files(file_scopes)
- ast2_builder.process_all()
- print(f"donezo {file_name} idx={idx}")
- except Exception as e:
- print(f"failure: idx={idx} {file_name}", file=sys.stderr)
- raise e
- # print(contract_source)
- # if idx is not None:
- # with open(f"../example/errors/Contract{idx}.sol", "w", encoding='utf-8') as text_file:
- # text_file.write(contract_source)
- finally:
- idx += 1
-
-
-
-if __name__ == '__main__1':
- pp.install_extras()
- logging.basicConfig( level=logging.DEBUG)
- # p = Path('../example/TestInput.json').resolve()
- # with p.open(mode='r', encoding='utf-8') as f:
- # data = f.read()
- # input = jsons.loads(data, StandardJsonInput)
- # print(input)
- # x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
- # print(x.name, x.hometown.name, x.hometown.id)
-
- # base_dir = 'C:/Users/Bilal/Downloads/solidity-examples-main/solidity-examples-main/contracts'
- base_dir = 'F:/Zellic/Workspace/solidity-parser/testcases/0.1.3'
- # base_dir = 'C:/Users/bibl/Downloads/ERC721A/contracts'
- # base_dir = 'C:/Users/bibl/Downloads/debridge-contracts-v1'
- # base_dir = 'F:/Zellic/Workspace/solidity-parser/testcases'
- # lets say we're in the /examples folder and go backwards to StargateComposed.sol in CLI
- # cwd = 'C:/Users/Bilal/Downloads/solidity-examples-main/solidity-examples-main/contracts/examples'
- # node_modules_dir = 'C:/Users/Bilal/node_modules'
- # node_modules_dir = 'C:/Users/bibl/AppData/Roaming/npm/node_modules'
- vfs = VirtualFileSystem(base_path=base_dir,
- # cwd=cwd,
- include_paths=[])
-
- # vfs.process_cli_input_file('C:/Users/Bilal/Downloads/solidity-examples-main/solidity-examples-main/contracts/StargateComposed.sol')
- # vfs.process_cli_input_file('C:/Users/Bilal/Downloads/solidity-examples-main/solidity-examples-main/contracts/examples/ExampleOFT.sol')
- # vfs.process_cli_input_file('.././StargateComposed.sol')
-
- # vfs.process_standard_json('../example/TestInput.json')
-
- symtab_builder = symtab.Builder2(vfs)
-
- # file_scope = builder.process_file('@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol')
- # contract_scope = file_scope.find('Initializable')
-
- # file_scope = builder.process_file('lzApp/NonblockingLzApp.sol')
- # contract_scope = file_scope.find('NonblockingLzApp')[0].value
-
- # file_scope = builder.process_file('@openzeppelin/contracts/token/ERC721/ERC721.sol')
- # contract_scope = file_scope.find('ERC721')[0].value
-
- # pp.pprint(contract_scope[0].value)
- ast2_builder = Builder2()
-
- # b2.define_skeleton(contract_scope, file_scope.source_unit_name)
-
- all_files = [y for x in os.walk(base_dir) for y in glob(os.path.join(x[0], '*.sol'))]
- all_files = [r[len(base_dir)+len('\\'):] for r in all_files]
- all_files = [f'./{f}' for f in all_files]
-
- # print(all_files)
-
- all_files = ['./SelfUsing.sol']
-
- for f in all_files:
- fs = symtab_builder.process_or_find_from_base_dir(f)
- ast2_builder.enqueue_files([fs])
- # for s in fs.symbols.values():
- # if len(s) != 1 or s[0].parent_scope != fs:
- # continue
- # n = s[0].value
- # if not hasattr(n, 'ast2_node') and ast2_builder.is_top_level(n):
- # ast2_node = ast2_builder.define_skeleton(n, fs.source_unit_name)
- # print(ast2_node)
- ast2_builder.process_all()
-
- us = ast2_builder.get_top_level_units()
- for p in us[1].parts:
- print(p.code.code_str())
- # print(us)
- # fs = symtab_builder.process_or_find_from_base_dir('contracts/libraries/Flags.sol')
- # for s in fs.symbols.values():
- # if len(s) != 1:
- # continue
- # n = s[0].value
- # if not hasattr(n, 'ast2_node') and ast2_builder.is_top_level(n):
- # ast2_builder.define_skeleton(n, fs.source_unit_name)
-
-
- ast2_builder.process_all()
-
- print("donezo")
-
-
- # syms = [x for xs in builder.root_scope.symbols.values() for x in xs if isinstance(x, symtab.FileScope)]
- # print(syms)
- # c2 = contract_scope[0].value.ast2_node
- # c2.get_children()
- # with open('output.txt', 'wt') as out:
- # pp.pprint(c2, stream=out)
-
- # print([str(c.value.name) for c in c3_linearise(contract_scope)])
-
- # funcanalysis.dfs(contract_scope[0].value)
- # print(contract_scope.get_local_method('swapNativeForNative'))
-
-if __name__ == '__main__1':
- # base_dir = 'C:/Users/Bilal/Downloads/contracts-30xx-only.tar/contracts-30xx-only'
- # all_files = [os.path.join(dp, f) for dp, dn, filenames in os.walk(base_dir) for f in filenames]
- # all_files = ['C:/Users/Bilal/Downloads/contracts-30xx-only.tar/contracts-30xx-only\\contracts\\30\\00\\30002861577da4ea6aa23966964172ad75dca9c7']
- # # start_idx = 10516
- # start_idx = 0
- # #
- # idx = 0
- # for info in get_contracts_from_descriptors(all_files):
- # if idx >= start_idx:
- # try_parse_contract(*info, idx=idx)
- # idx += 1
-
- input_src = open(
- 'F:/Zellic/Workspace/solidity-parser/testcases/08_22/SourceUnits.sol',
- # 'C:/Users/bibl/Downloads/x/RLPReader.sol',
- 'r').read()
-
-
- print(asthelper.make_ast(input_src))
-
- # try_parse_contract('ft', 8, input_src, None)
-
- # lexer = SolidityLexer088(InputStream(input_src))
- # stream = CommonTokenStream(lexer)
- # parser = SolidityParser088(stream)
- # ast_parser = Parser088()
- #
- # tree = parser.sourceUnit()
- # source_units = tree.children
-
- # symtab_builder = symtab.Builder2(None)
-
- # ast_nodes = list(map(ast_parser.make, source_units))
-
- # file_path = Path('../example/AaveToken.sol').resolve()
- # symtab_builder.process_file(file_path, ast_nodes)
-
- # base_dir = '../example/Aave/'
- # base_dir = 'C:/Users/Bilal/Downloads/solidity-examples-main/solidity-examples-main/contracts'
-
- # base_dir = 'C:/Users/Bilal/Downloads/solidity-examples-main/solidity-examples-main/contracts/mocks'
- # file_paths = [os.path.join(dirpath, f) for (dirpath, dirnames, filenames) in os.walk(base_dir) for f in filenames if f.endswith('.sol')]
-
- # all_ast_nodes = []
- # for fp in file_paths:
- # # if not fp.endswith('ProxyOFTV2.sol'):
- # # continue
- # ast_nodes = get_ast(fp)
- # full_path = Path(fp).resolve()
- # symtab_builder.process_file(full_path, ast_nodes)
- # all_ast_nodes = all_ast_nodes + ast_nodes
-
-
- # for su in source_units:
- # u = ast_parser.make(su)
- #
- # if isinstance(u, solnodes.ContractDefinition) and str(u.name) == 'ClockAuctionBase':
- # symtab_builder.process_source_unit(u)
-
- # root_scope = symtab_builder.root_scope
-
- # print(root_scope)
-
- # file_scope = root_scope.follow_find('', '', '',
- # '', '',
- # '', '', '', '')
- # print(root_scope)
- # contract_scope = file_scope.find_local('AaveToken')
- # This text is 'ITransferHook'
- # itransferhook_type = contract_scope.find_local('_aaveGovernance').value.var_type.text
- # scope that is valid at this decl
- # aavegovernance_state_var_decl_scope: symtab.Scope = contract_scope
-
- # print(aavegovernance_state_var_decl_scope.find(itransferhook_type))
- # print(root_scope)
- # print(contract_scope.find('VersionedInitializable').resolve('VersionedInitializable'))
-
- # scope_in_bid_func = root_scope.find('ClockAuctionBase').find('_bid')
-
- # im in bid function, now I see the symbol 'Auction' => find it for me pls
-
- # auction_sym = scope_in_bid_func.find('Auction')
- #
- # print(root_scope)
-
- # for n in all_ast_nodes:
- # if n and isinstance(n, solnodes.ContractDefinition) and n.name.text == 'StargateComposed':
- # dfs(n)
- # print(len(all_ast_nodes))
-
-
- # if hasattr(u, 'parts'):
- # parts = u.parts
-
- # for p in parts:
- # if isinstance(p, solnodes.FunctionDefinition):
- # arg_string = ', '.join(map(str, p.args))
- # return_string = ', '.join(map(str, p.returns))
- # print(f"FUNC {u.name}.{p.name} takes ({arg_string}) and returns ({return_string})")
- #
- # pp.pprint(p.code)
- #
- #
- # break
-
-
-
-if __name__ == "__main__1":
- # c = Contract('weth9', ContractType.CONTRACT, False, [])
- # print(c)
- pp.install_extras()
- input_src = open(
- # sys.argv[1],
- 'example/cryptokitties.sol',
- # '../example/greedy-airdropper.sol',
- # '../example/AaveToken.sol',
- 'r').read()
- # minor_vers = get_minor_ver(input_src)
- # for obj in collect_top_level_objects(input_src, minor_vers):
- # print(f'=== {obj.name} ===')
- # print(obj.content)
- # print(obj)
- data = InputStream(input_src)
- # lexer = SolidityLexer(data)
- # stream = CommonTokenStream(lexer)
- # parser = SolidityParser(stream)
-
- # tree = parser.sourceUnit()
- # source_units = tree.children
-
- # p = Parser060()
-
- # for su in source_units:
- # visit(su)
- # u = p.make(su)
- # pp.pprint(u)
diff --git a/setup.py b/setup.py
index 782bb8c..0992dcc 100644
--- a/setup.py
+++ b/setup.py
@@ -26,7 +26,7 @@ def gen(self):
setup(
name='solidity-parser',
- version='0.1.15',
+ version='0.1.16',
install_requires=[
"antlr4-python3-runtime==4.11.1",
diff --git a/src/solidity_parser/ast/ast2builder.py b/src/solidity_parser/ast/ast2builder.py
index ee9d8bd..e007108 100644
--- a/src/solidity_parser/ast/ast2builder.py
+++ b/src/solidity_parser/ast/ast2builder.py
@@ -1,10 +1,10 @@
import typing
-from dataclasses import dataclass, replace as copy_dataclass
-from typing import List, Union, Dict, Deque
+from dataclasses import dataclass
+from typing import List, Union, Dict, Deque, cast, Optional
from collections import deque, defaultdict
from copy import deepcopy
-from solidity_parser.ast import solnodes as solnodes1
+from solidity_parser.ast import nodebase, solnodes as solnodes1, types as soltypes
from solidity_parser.ast import solnodes2 as solnodes2, symtab
import logging
@@ -14,21 +14,41 @@
from solidity_parser import errors
-# This is not a real type, hence why it's not defined in the AST2 nodes file, but the solidity
-# compiler allows for
-@dataclass
-class FloatType(solnodes2.Type):
- value: float
+
+
+T = typing.TypeVar('T')
class ErrorHandler:
+ """
+ Keeps track of what AST2Builder is doing and captures the line tracking information when errors happen. Also wraps
+ Python errors in our own errors types if required and provides assertion failure checking.
+
+ The general idea of this class is to make sure AST2Builder operations return consistent error types by wrapping
+ them in CodeProcessingErrors so that the client can catch and decide what to do with them.
+ """
+
def __init__(self, create_state, quiet_errors=True):
+ """
+ :param create_state: A function used to compute the state of the builder for a node when an error context
+ wrapped function is called
+ :param quiet_errors: Whether to throw an error immediately or store it in the caught_errors list
+ """
+
+ # whether to throw a caught error immediately or store it in the caught_errors list for a client to consume
+ # later, this is used for testing where fast errors can be caught and fail the test quickly
self.quiet_errors = quiet_errors
+ self.caught_errors = []
+ # current state of the builder
self.state = None
+ # state creator function, takes a node, returns a state
self.create_state = create_state
- self.caught_errors = []
def handle_processing_error(self, error: errors.CodeProcessingError):
+ """
+ Error callback handler for AST2Builder functions to call when a CodeProcessingError (only) occurs.
+ """
+ # reraise if not quiet
if self.quiet_errors:
logging.getLogger('AST2').error(f'Processing error: {error.args[0]}')
self.caught_errors.append(error)
@@ -36,23 +56,32 @@ def handle_processing_error(self, error: errors.CodeProcessingError):
raise error
@staticmethod
- def make_processing_error_args(message: str, node: solnodes1.Node) -> errors.CPEArgs:
+ def make_processing_error_args(message: str, node: solnodes1.AST1Node) -> errors.CPEArgs:
+ """ Helper to make the input args tuple for a CodeProcessingError from a message and AST1 node """
file_scope = node.scope.find_first_ancestor_of(symtab.FileScope)
return message, file_scope.source_unit_name, node.linenumber(), node.offset()
def with_error_context(self, func):
+ """
+ Decorator that takes a function, f, and wraps it in a function that captures the current state of the builder
+ before executing f and restores the state afterwards. If any errors occur in the process, a CodeProcessingError
+ (specifically an UnexpectedCodeProcessingError) is raised, which should be allowed to propagate to the client of
+ the builder.
+ """
@functools.wraps(func)
def wrapped_function(node, *args, **kwargs):
# Store current state
prev_state = self.state
- # Update current state
+ # Create a new state for the node
state = self.create_state(node)
self.state = state
try:
result = func(node, *args, **kwargs)
except errors.CodeProcessingError:
+ # CPE, reraise
raise
except Exception as e:
+ # Non CPE, wrap in CPE
error_args = self.make_processing_error_args(e.args[0] if e.args else f'{type(e)}', state.current_node)
raise errors.UnexpectedCodeProcessingError(*error_args, e) from e
finally:
@@ -61,17 +90,33 @@ def wrapped_function(node, *args, **kwargs):
return result
return wrapped_function
- def todo(self, node):
+ def todo(self, node) -> T:
+ """
+ Forces an error if the node is not supported by the builder. Since it always raises, the return type is fully
+ polymorphic and can be used by the builder to do anything.
+ E.g. a common pattern is to return the result of this function to mark the end of control flow in the builder
+ code return self.error_handler.todo(node)
+ """
return self._todo(node)
def error(self, msg, *predicates):
+ """
+ Raises an error with the given message if any of the predicates fail. This is used for user level errors, i.e.
+ the input code is invalid
+ """
return self._error(msg, *predicates)
def assert_error(self, msg, *predicates):
+ """
+ Raises an assertion error with the given message if any of the predicates fail, very similar to error but used
+ for 'internal' errors, i.e. compiler assumptions that must pass
+ """
return self._assert_error(msg, *predicates)
- def _todo(self, node):
+ def _todo(self, node) -> T:
+ # this always raises an error, so let the return type be suitable for any use case, e.g. return _todo
self._error(f'{type(node)} not supported/implemented')
+ return None
def _error(self, msg, *predicates):
# Used for user level errors, i.e. the input code has an issue
@@ -88,17 +133,27 @@ def _assert_error(self, msg, *predicates):
class TypeHelper:
- def __init__(self, builder, error_handler: ErrorHandler):
+ """
+ Helper class for computing AST2 types from AST1 nodes. This is required because AST1 nodes are not linked and do not
+ have type information associated with some nodes, i.e. the node trees aren't able to compute types on their own.
+ """
+ def __init__(self, builder: 'Builder', error_handler: ErrorHandler):
self.builder = builder
self.error_handler = error_handler
@staticmethod
def any_or_all(args):
+ """ Returns True if any or all args are True """
return (len(args) == 0) or (any(args) == all(args))
- def create_filter_using_scope(self, base_type: solnodes2.Type):
+ def create_filter_using_scope(self, base_type: soltypes.Type):
+ # creates a filter for searching in the symtab. This is required because when a using statement is seen, all of
+ # the functions from the library are imported into the current scope, even if they don't match the type
+ # specified in the using statement. This filter checks if the type in the using statement matches the given
+ # base_type
def test_predicate(s: symtab.Symbol):
if isinstance(s, symtab.UsingFunctionSymbol):
+ # override type is the type specified in the using statement
override_type = self.get_expr_type(s.override_type)
return override_type.can_implicitly_cast_from(base_type)
else:
@@ -106,21 +161,43 @@ def test_predicate(s: symtab.Symbol):
return test_predicate
def get_current_contract_type(self, node) -> solnodes2.ResolvedUserType:
+ """ Returns the ResolvedUserType the given node is declared in """
return self.get_contract_type(self.builder.get_declaring_contract_scope(node))
- def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=False, function_callee=False) -> solnodes2.Type:
- if isinstance(expr, solnodes1.Type):
+ def get_expr_type(self, expr: solnodes1.Expr | soltypes.Type, allow_multiple=False, force_tuple=False, function_callee=False) -> typing.Union[solnodes2.Types, list[solnodes2.Types]]:
+ """
+ Main helper function that computes the AST2 type of the given AST1 expression
+
+ :param expr: The AST1 expression to type, may be a Type also as types are part of both the AST1 and AST2 nodeset
+ :param allow_multiple: Changes the return of this function to a list of types instead of a single type. This is
+ required for expressions that may need extra contextual information to return a single
+ resolved Type, e.g. the callee of a function call without its arguments may resolve to
+ multiple callsites and if this is set to True, the return type will be a list of function
+ types
+ :param force_tuple: Forces the return type to be a TupleType instead of a single type in cases where it's
+ ambiguous, e.g. the expression (x) can be either a bracket expression or a tuple expression
+ :param function_callee: Whether the expression is the callee of a function call, required to compute the type of
+ state variable lookups as Solidity generates getter functions if the variable is used as
+ a function callee
+ :return: The AST2 type of the expression or a list of types if allow_multiple is True
+ """
+
+ if isinstance(expr, soltypes.Type):
+ # already have a type, either return it or resolve it to make sure it's AST2 and not AST1 only
return self.map_type(expr)
elif isinstance(expr, solnodes1.Ident):
text = expr.text
if text == 'this':
return self.get_current_contract_type(expr)
elif text == 'super':
- # RTU.value is a Ref[Contract/InterfaceDef] which is what SuperType takes
+ # contract_type.value is a Ref[Contract/InterfaceDef] which is what SuperType takes
contract_type = self.get_current_contract_type(expr)
return solnodes2.SuperType(contract_type.value)
else:
+ # lookup a single unqualified Ident in the current scope(expr.scope). Note this path ISN'T taken for
+ # qualified lookups (e.g. x.y)
if allow_multiple:
+ # return all matching symbol types, TODO: should use ACCEPT_INHERITABLE here also?
return [self.symbol_to_ast2_type(s, function_callee=function_callee) for s in expr.scope.find(text)]
else:
inheritable_predicate = symtab.ACCEPT_INHERITABLE(expr.scope)
@@ -128,31 +205,40 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
if not symbols:
self.error_handler.error(f'Unresolved reference to {expr.text}')
- assert False # unreachable
+ assert False # unreachable as the above error is always raised
if len(symbols) == 1:
return self.symbol_to_ast2_type(symbols[0], function_callee=function_callee)
- # for now check they're all the same, this might be wrong and we might have to find the highest type
+ # we only care about the type here and not the symbols, so if all the types are the same, just
+ # return the type of the first: this might be wrong and we might have to find the highest type
# in the lattice
possible_types = [self.symbol_to_ast2_type(s, function_callee=function_callee) for s in symbols]
types_the_same = [possible_types[0] == t for t in possible_types[1:]]
- self.error_handler.error(f'Need the same types: {types_the_same}', types_the_same)
-
+ self.error_handler.error(f'Need the same types: {possible_types}', types_the_same)
return possible_types[0]
elif isinstance(expr, solnodes1.GetMember):
+ # similar to the Ident case, but we have to resolve the base type first to get the scope in which we will
+ # look up the member name
base_type = self.get_expr_type(expr.obj_base)
member = expr.name.text
- find_direct_scope = isinstance(expr.obj_base, (solnodes1.BytesType, solnodes1.StringType))
+ # Solidity has bytes.concat and string.concat, when this happens the obj_base is bytes or string (subclass
+ # of Type, not Ident) and the member is concat. In that case the typekey used for the base type is different
+ # so that the builtin object with the concat function can be found
+ find_direct_scope = isinstance(expr.obj_base, (soltypes.BytesType, soltypes.StringType))
scopes = self.scopes_for_type(expr, base_type, use_encoded_type_key=not find_direct_scope)
if allow_multiple:
for s in scopes:
+ # search with the using filter here as qualified lookups can resolve to functions introduced by the
+ # using statement
symbols = s.find(member, predicate=self.create_filter_using_scope(base_type))
if symbols:
return [self.symbol_to_ast2_type(s, function_callee=function_callee) for s in symbols]
+ return []
else:
+ # TODO: do we need the using filter here as well?
for s in scopes:
symbols = s.find(member)
if symbols:
@@ -161,12 +247,14 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
all_same_types = [symbol_types[0] == s_t for s_t in symbol_types]
self.error_handler.error('Multiple symbols matched with different types', all_same_types)
return symbol_types[0]
+
+ # TODO: change this to error_handler.todo call
return []
elif isinstance(expr, solnodes1.Literal):
value = expr.value
if isinstance(value, bool):
# this needs to go before the int check as bool is a subclass of int in python
- return solnodes2.BoolType()
+ return soltypes.BoolType()
elif isinstance(value, (int, float)):
if isinstance(value, float):
# Try and create an integer out of this float literal. If that's not possible, then the caller
@@ -176,7 +264,7 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
# This can happen because compiletime floats are allowed in solidity for expressions
# that are evaluated at compiletime. E.g. instead of 0.01 ether which would give full_value
# an integer value, we could have 0.01 * 1 ether as a binary expr
- return FloatType(full_value)
+ return soltypes.FloatType(full_value)
full_value = int(full_value)
else:
full_value = value
@@ -184,7 +272,7 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
value = full_value
if value == 0:
- return solnodes2.PreciseIntType(is_signed=False, size=8, real_bit_length=1)
+ return soltypes.PreciseIntType(is_signed=False, size=8, real_bit_length=1)
if value > 0:
# uint
@@ -202,13 +290,14 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
bytes += 1
bits = bytes * 8
- return solnodes2.PreciseIntType(is_signed=signed, size=bits, real_bit_length=full_value.bit_length())
+ return soltypes.PreciseIntType(is_signed=signed, size=bits, real_bit_length=full_value.bit_length())
elif isinstance(value, str):
# TODO: maybe need to revise to a different len calculation based on the docs
- return solnodes2.PreciseStringType(real_size=len(value))
+ return soltypes.PreciseStringType(real_size=len(value))
elif isinstance(value, tuple):
+ # this is for bracketed expressions, may or may not be a tuple expression
type_args = [self.map_as_type_arg(arg) for arg in value]
- are_type_args = [isinstance(arg, (solnodes1.Type, solnodes2.Type)) for arg in type_args]
+ are_type_args = [isinstance(arg, soltypes.Type) for arg in type_args]
self.error_handler.assert_error('Tuple type args must be any or all', TypeHelper.any_or_all(are_type_args))
@@ -219,27 +308,29 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
if len(type_args) == 1 and not force_tuple:
return self.map_type(type_args[0])
else:
- return solnodes2.TupleType([self.map_type(t) for t in type_args])
+ return soltypes.TupleType([self.map_type(t) for t in type_args])
self.error_handler.assert_error('Expected all exprs in tuple',
all([isinstance(e, solnodes1.Expr) for e in value]))
if len(value) == 1:
if force_tuple:
- return solnodes2.TupleType([self.get_expr_type(value[0])])
+ return soltypes.TupleType([self.get_expr_type(value[0])])
else:
# Bracketed expressions, not tuples, e.g. (x).y() , (x) isn't a tuple so unpack here
return self.get_expr_type(value[0])
else:
- return solnodes2.TupleType([self.get_expr_type(e) for e in value])
+ # multiple expressions, definitely a tuple
+ return soltypes.TupleType([self.get_expr_type(e) for e in value])
else:
return self.error_handler.todo(value)
elif isinstance(expr, solnodes1.GetArrayValue):
+ # array index lookups can be either a mapping or an array lookup
base_type = self.get_expr_type(expr.array_base)
if base_type.is_mapping():
- return base_type.dst
+ return cast(soltypes.MappingType, base_type).dst
elif base_type.is_array():
- return base_type.base_type
+ return cast(soltypes.ArrayType, base_type).base_type
else:
return self.error_handler.todo(base_type)
elif isinstance(expr, solnodes1.GetArraySlice):
@@ -249,7 +340,8 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
t1 = self.get_expr_type(expr.left, force_tuple=expr.op.name.startswith('ASSIGN'))
t2 = self.get_expr_type(expr.right)
- if t1.is_user_type() and t1.value.x.is_udvt() and t2.is_user_type() and t2.value.x.is_udvt():
+ if (t1.is_user_type() and cast(solnodes2.ResolvedUserType, t1).value.x.is_udvt() and t2.is_user_type()
+ and cast(solnodes2.ResolvedUserType, t2).value.x.is_udvt()):
member_symbol = self.builder.find_bound_operator_symbol(expr, [t1, t2])
output_params = member_symbol.value.returns
self.error_handler.assert_error('Not handled', len(output_params) == 1)
@@ -257,10 +349,10 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
if expr.op in [solnodes1.BinaryOpCode.BOOL_AND, solnodes1.BinaryOpCode.BOOL_OR, solnodes1.BinaryOpCode.EQ,
solnodes1.BinaryOpCode.NEQ]:
- return solnodes2.BoolType()
+ return soltypes.BoolType()
elif expr.op in [solnodes1.BinaryOpCode.LTEQ, solnodes1.BinaryOpCode.LT, solnodes1.BinaryOpCode.GT,
solnodes1.BinaryOpCode.GTEQ]:
- return solnodes2.BoolType()
+ return soltypes.BoolType()
elif expr.op in [solnodes1.BinaryOpCode.LSHIFT, solnodes1.BinaryOpCode.RSHIFT,
solnodes1.BinaryOpCode.ASSIGN_LSHIFT, solnodes1.BinaryOpCode.ASSIGN_RSHIFT]:
# result of a shift has the type of the left operand (from docs)
@@ -286,11 +378,11 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
self.error_handler.assert_error(f'Invalid assign types {t1}, vs {t2}',
(t1.is_int() and t2.is_int())
- or (solnodes2.is_byte_array(t1) and solnodes2.is_byte_array(t2))
- or (solnodes2.is_byte_array(t1) and t2.is_int()))
+ or (t1.is_byte_array() and t2.is_byte_array())
+ or (t1.is_byte_array() and t2.is_int()))
if t1.is_int(): # t2 is also an int here
- return t1 if t1.size > t2.size else t2
+ return t1 if cast(soltypes.IntType, t1).size > cast(soltypes.IntType, t2).size else t2
else:
if not t2.is_tuple():
# tuple assign, note the lhs can have a subset of the RHS, e.g. (a, ) = f()
@@ -309,10 +401,10 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
if t1.is_int():
# if they're both ints, then take the bigger type
- return t1 if t1.size > t2.size else t2
+ return t1 if cast(soltypes.IntType, t1).size > cast(soltypes.IntType, t2).size else t2
elif t1.is_literal_type() and t2.is_literal_type() and t1.is_string() and t2.is_string():
# both precise string types but different sizes, take the biggest one
- return t1 if t1.real_size > t2.real_size else t2
+ return t1 if cast(soltypes.PreciseStringType, t1).real_size > cast(soltypes.PreciseStringType, t2).real_size else t2
else:
try:
assert t1 == t2
@@ -330,7 +422,7 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
elif isinstance(expr, solnodes1.UnaryOp):
expr_type = self.get_expr_type(expr.expr)
- if expr_type.is_user_type() and expr_type.value.x.is_udvt():
+ if expr_type.is_user_type() and cast(solnodes2.ResolvedUserType, expr_type).value.x.is_udvt():
member_symbol = self.builder.find_bound_operator_symbol(expr, [expr_type])
output_params = member_symbol.value.returns
self.error_handler.assert_error('Not handled', len(output_params) == 1)
@@ -340,52 +432,52 @@ def get_expr_type(self, expr: solnodes1.Expr, allow_multiple=False, force_tuple=
solnodes1.UnaryOpCode.SIGN_POS, solnodes1.UnaryOpCode.BIT_NEG]:
return expr_type
elif expr.op == solnodes1.UnaryOpCode.BOOL_NEG:
- return solnodes2.BoolType()
+ return soltypes.BoolType()
else:
return self.error_handler.todo(expr.op)
elif isinstance(expr, solnodes1.CallFunction):
return self.get_function_expr_type(expr, allow_multiple=allow_multiple)
elif isinstance(expr, solnodes1.CreateMetaType):
- return solnodes2.MetaTypeType(self.map_type(expr.base_type))
+ return soltypes.MetaTypeType(self.map_type(expr.base_type))
elif isinstance(expr, solnodes1.New):
return self.map_type(expr.type_name)
elif isinstance(expr, solnodes1.PayableConversion):
- return solnodes2.AddressType(is_payable=True)
+ return soltypes.AddressType(is_payable=True)
elif isinstance(expr, solnodes1.NamedArg):
return self.get_expr_type(expr.value)
elif isinstance(expr, solnodes1.NewInlineArray):
- arg_types = [self.get_expr_type(arg) for arg in expr.elements]
+ arg_types: list[soltypes.Type] = [self.get_expr_type(arg) for arg in expr.elements]
are_ints = any([t.is_int() for t in arg_types])
if are_ints:
# if any of the elements is signed, the resultant type can't bn unsigned
# e.g. [-1, 0, 0] can't be uint8[]
- is_signed = any([t.is_signed for t in arg_types])
+ is_signed = any([cast(soltypes.IntType, t).is_signed for t in arg_types])
max_real_bit_length = 0
max_total_length = 0
for t in arg_types:
- max_total_length = max(max_total_length, t.size)
+ max_total_length = max(max_total_length, cast(soltypes.IntType, t).size)
if t.is_literal_type():
- max_real_bit_length = max(max_real_bit_length, t.real_bit_length)
+ max_real_bit_length = max(max_real_bit_length, cast(soltypes.PreciseIntType, t).real_bit_length)
if any([not t.is_literal_type() for t in arg_types]):
# if there are any non precise ones, the whole thing can't be precise, e.g. [0, 1, this.myInt] can't
# have a base_type of uint8(1), instead it must be uint(T(this.myInt))
- base_type = solnodes2.IntType(is_signed, max_total_length)
+ base_type = soltypes.IntType(is_signed, max_total_length)
else:
- base_type = solnodes2.PreciseIntType(is_signed, max_total_length, max_real_bit_length)
+ base_type = soltypes.PreciseIntType(is_signed, max_total_length, max_real_bit_length)
- return solnodes2.FixedLengthArrayType(base_type, len(expr.elements))
+ return soltypes.FixedLengthArrayType(base_type, len(expr.elements))
else:
self.error_handler.assert_error(f'Different element types: {arg_types}', all([arg_types[0] == t for t in arg_types]))
- return solnodes2.FixedLengthArrayType(arg_types[0], len(expr.elements))
+ return soltypes.FixedLengthArrayType(arg_types[0], len(expr.elements))
return self.error_handler.todo(expr)
def get_function_expr_type(self, expr, allow_multiple=False, return_target_symbol=False):
callee = expr.callee
- if isinstance(callee, solnodes1.Type):
+ if isinstance(callee, soltypes.Type):
if callee.is_address():
# special case where address(uint160) maps to address payable:
# see https://docs.soliditylang.org/en/develop/050-breaking-changes.html
@@ -393,12 +485,12 @@ def get_function_expr_type(self, expr, allow_multiple=False, return_target_symbo
arg_type = self.get_expr_type(expr.args[0])
if arg_type.is_int() and not arg_type.is_signed and arg_type.size == 160:
- return solnodes2.AddressType(is_payable=True)
+ return soltypes.AddressType(is_payable=True)
# e.g. int(...), string(...), address(...) => cast expr
return self.map_type(callee)
elif isinstance(callee, solnodes1.Ident) and callee.text == 'address':
- return solnodes2.AddressType(is_payable=False)
+ return soltypes.AddressType(is_payable=False)
arg_types = [self.get_expr_type(arg) for arg in expr.args]
@@ -408,7 +500,7 @@ def get_function_expr_type(self, expr, allow_multiple=False, return_target_symbo
callable_ttypes = [callable_ttypes]
def is_cast_call(t):
- return isinstance(t, solnodes2.Type) and not t.is_function() and not t.is_mapping()
+ return isinstance(t, soltypes.Type) and not t.is_function() and not t.is_mapping()
# de-deplicate the callables. This is because we don't have 'base' information for these types like we do
# when we refine function calls in the builder. The get_expr_type call can return functions that are overriden
@@ -440,6 +532,7 @@ def is_cast_call(t):
candidates = []
for ttype in callable_ttypes:
if ttype.is_function():
+ ttype: soltypes.FunctionType
# None is a sentinel, do NOT do 'if ft.inputs:'
if ttype.inputs is not None:
# match input types
@@ -452,6 +545,7 @@ def is_cast_call(t):
candidates.append(ttype.outputs)
continue
elif ttype.is_mapping():
+ ttype: soltypes.MappingType
flattened_types = ttype.flatten()
self.error_handler.assert_error(f'{flattened_types} vs {arg_types}',
@@ -465,7 +559,7 @@ def is_cast_call(t):
self.error_handler.todo(ttype)
if len(candidates) != 1:
- callable_ttypes = self.get_expr_type(callee, allow_multiple=True)
+ callable_ttypes = self.get_expr_type(callee, allow_multiple=True, function_callee=True)
self.error_handler.error(f'Can\'t resolve call')
output_types = candidates[0]
@@ -486,15 +580,24 @@ def is_cast_call(t):
if len(output_types) == 1:
return output_types[0]
else:
- return solnodes2.TupleType(output_types)
+ return soltypes.TupleType(output_types)
def map_as_type_arg(self, arg):
- # grammar shenanigans again...
+ """
+ This function tries to force the given expr argument into a type if it looks like a type
+
+ The supplied grammar is ambiguous and sometimes parses types as expression e.g. byte[100] would end up as an
+ array access instead of a fixed length byte array. I've only really seen this happen for arguments of function
+ calls, i.e. in abi.decode hence the name of the function. Should probably see if this happens in other places in
+ the grammar too...
+ """
+
# sometimes stuff like uint[] gets parsed as GetArrayValue(array_base=IntType(...), index=None))
- if isinstance(arg, solnodes1.Type):
- # simple case
+ if isinstance(arg, soltypes.Type):
+ # "base case", it's a Type already so it's definitely a type :)
return self.map_type(arg)
elif isinstance(arg, solnodes1.Ident):
+ # TODO: this can be improved: better lookup functions now exist compared to find
# lookup the ident in the current scope and if it's a top level type, it's a type
symbols = arg.scope.find(arg.text)
if len(symbols) == 1:
@@ -506,8 +609,11 @@ def map_as_type_arg(self, arg):
if self.builder.is_top_level(resolved_sym.value):
return self.symbol_to_ast2_type(resolved_sym)
elif isinstance(arg, solnodes1.GetMember):
+ # Happens with qualified types, e.g. MyC.MyB
+ # FIXME: want to get rid of the refine_expr call here and use a pure AST1 solution as refine_expr has side
+ # effects on the arg
possible_type = self.builder.refine_expr(arg)
- if isinstance(possible_type, solnodes2.Type):
+ if isinstance(possible_type, soltypes.Type):
return possible_type
elif isinstance(arg, solnodes1.GetArrayValue):
# try and coerce the base node into a type, this handles cases where the array_base
@@ -515,7 +621,7 @@ def map_as_type_arg(self, arg):
base_ttype = None
possible_base_ttype = self.builder.refine_expr(arg.array_base, allow_type=True)
- if possible_base_ttype and isinstance(possible_base_ttype, solnodes2.Type):
+ if possible_base_ttype and isinstance(possible_base_ttype, soltypes.Type):
base_ttype = possible_base_ttype
else:
return arg
@@ -523,38 +629,51 @@ def map_as_type_arg(self, arg):
if arg.index:
# e.g. bytes32[100]
if isinstance(arg.index, solnodes1.Literal):
- return solnodes2.FixedLengthArrayType(base_ttype, int(arg.index.value))
+ return soltypes.FixedLengthArrayType(base_ttype, int(arg.index.value))
else:
# e.g. MyType[]
- return solnodes2.ArrayType(base_ttype)
+ return soltypes.ArrayType(base_ttype)
# base case
return arg
def param_types(self, ps):
+ """ Returns the types of the given parameters """
if not ps:
return []
return [self.map_type(p.var_type) for p in ps]
- def symbol_to_ast2_type(self, symbol, function_callee=False) -> solnodes2.Type:
+ def symbol_to_ast2_type(self, symbol, function_callee=False) -> solnodes2.Types:
+ """
+ Computes the AST2 type of the given symtab Symbol
+ """
+
if isinstance(symbol, symtab.FileScope):
- # apparently you can prefix with a file name now? e.g. MyErrors.ErrorX() where MyErrors is the imported 'MyErrors.sol' file and
- # 'ErrorX' is a free function/error in that file
+ # apparently you can prefix with a file name now? e.g. MyErrors.ErrorX() where MyErrors is the imported
+ # 'MyErrors.sol' file and'ErrorX' is a free function/error in that file
return self.get_contract_type(symbol)
elif isinstance(symbol, symtab.UsingFunctionSymbol):
- value = symbol.value
+ # need an unresolved symbol for this as called res_syms_single on a UsingFunctionSymbol gives the base
+ # ModFunErrEvt symbol
+
+ # cast for type checker, could be further refined as just FunctionDefinition
+ value = cast(solnodes1.ModFunErrEvt, symbol.value)
# X.abc(), remove the type of X to the start of the input types
- return solnodes2.FunctionType(self.param_types(value.parameters)[1:], self.param_types(value.returns))
+ return soltypes.FunctionType(self.param_types(value.parameters)[1:],
+ self.param_types(value.returns),
+ self.builder.modifiers(value))
+ # can resolve now
symbol = symbol.res_syms_single()
+
if isinstance(symbol, symtab.BuiltinObject):
if v := symbol.value:
- # if this builtin object was created to scope a type, e.g. an byte[] or int256, etc, just
+ # if this builtin object was created to scope a type, e.g. a byte[] or int256, etc, just
# resolve to the type directly instead of shadowing it as a builtin type
self.error_handler.assert_error(f'Builtin symbol must be type: {type(v)}',
- isinstance(v, (solnodes1.Type, solnodes2.Type)))
+ isinstance(v, soltypes.Type))
return self.map_type(v)
else:
- return solnodes2.BuiltinType(symbol.name)
+ return soltypes.BuiltinType(symbol.name)
elif isinstance(symbol, symtab.BuiltinFunction):
# These input type checks need to be 'is not None' instead of just if symbol.input_types as some of these
# might be empty lists (meaning no inputs or outputs in the function) whereas 'None' indicates that the
@@ -562,15 +681,10 @@ def symbol_to_ast2_type(self, symbol, function_callee=False) -> solnodes2.Type:
# At the moment 'None' output_types is only used for abi.decode
input_types = [self.map_type(ttype) for ttype in symbol.input_types] if symbol.input_types is not None else None
output_types = [self.map_type(ttype) for ttype in symbol.output_types] if symbol.output_types is not None else None
- return solnodes2.FunctionType(input_types, output_types)
+ return soltypes.FunctionType(input_types, output_types, [])
elif isinstance(symbol, symtab.BuiltinValue):
ttype = symbol.ttype
-
- if isinstance(ttype, solnodes2.Type):
- # For builtin values that we create in scope_for_type, we pass in an AST2 Type instead of AST1 Type
- return ttype
- else:
- return self.map_type(ttype)
+ return self.map_type(ttype)
value = symbol.value
@@ -580,26 +694,28 @@ def symbol_to_ast2_type(self, symbol, function_callee=False) -> solnodes2.Type:
elif isinstance(value, (solnodes1.Parameter, solnodes1.Var)):
return self.map_type(value.var_type)
elif isinstance(value, solnodes1.FunctionDefinition):
- return solnodes2.FunctionType(self.param_types(value.parameters), self.param_types(value.returns))
+ return soltypes.FunctionType(self.param_types(value.parameters), self.param_types(value.returns), self.builder.modifiers(value))
elif isinstance(value, solnodes1.ErrorDefinition):
# AFAIK this is only used for MyError.selector
- return solnodes2.FunctionType(self.param_types(value.parameters), [])
+ return soltypes.FunctionType(self.param_types(value.parameters), [], [])
elif isinstance(value, solnodes1.EventDefinition):
# This can happen with old solidity contracts before the 'emit' keyword was created. In this case, an
# event is triggered by a function call e.g. MyEvent() instead of emit MyEvent()
- return solnodes2.FunctionType(self.param_types(value.parameters), [])
+ return soltypes.FunctionType(self.param_types(value.parameters), [], [])
elif isinstance(value, (solnodes1.StateVariableDeclaration, solnodes1.ConstantVariableDeclaration)):
# Mappings are stored as fields but have mapping types
field_type = self.map_type(value.var_type)
if function_callee:
# This is the case where a public state var is loaded via its autogenerated getter
+ modifiers = [solnodes2.VisibilityModifier(solnodes1.VisibilityModifierKind.EXTERNAL),
+ solnodes2.MutabilityModifier(solnodes1.MutabilityModifierKind.VIEW)]
if field_type.is_mapping():
flattened_types = field_type.flatten()
- return solnodes2.FunctionType(flattened_types[:-1], flattened_types[-1:])
+ return soltypes.FunctionType(flattened_types[:-1], flattened_types[-1:], modifiers)
elif field_type.is_array() and not field_type.is_byte_array_underlying():
- return solnodes2.FunctionType([solnodes2.UIntType()], [field_type.base_type])
+ return soltypes.FunctionType([soltypes.UIntType()], [field_type.base_type], modifiers)
else:
- return solnodes2.FunctionType([], [field_type])
+ return soltypes.FunctionType([], [field_type], modifiers)
return field_type
elif isinstance(value, solnodes1.StructMember):
return self.map_type(value.member_type)
@@ -610,10 +726,10 @@ def symbol_to_ast2_type(self, symbol, function_callee=False) -> solnodes2.Type:
isinstance(value.scope, symtab.EnumScope))
return self.symbol_to_ast2_type(value.scope)
elif isinstance(value, solnodes1.ModifierDefinition):
- return solnodes2.FunctionType(self.param_types(value.parameters), [])
+ return soltypes.FunctionType(self.param_types(value.parameters), [], self.builder.modifiers(value))
assert False, f'{type(value)}'
- def scopes_for_type(self, node: solnodes1.Node, ttype: solnodes2.Type, use_encoded_type_key=True) -> List[symtab.Scope]:
+ def scopes_for_type(self, node: solnodes1.AST1Node, ttype: solnodes2.Types, use_encoded_type_key=True) -> List[symtab.Scope]:
if isinstance(ttype, solnodes2.SuperType):
return c3_linearise(self.builder.get_declaring_contract_scope(node))
elif isinstance(ttype, solnodes2.ResolvedUserType):
@@ -653,12 +769,12 @@ def scopes_for_type(self, node: solnodes1.Node, ttype: solnodes2.Type, use_encod
# scopes.append(scope.find_type(solnodes1.AddressType(False)))
return scopes
- elif isinstance(ttype, solnodes2.BuiltinType):
+ elif isinstance(ttype, soltypes.BuiltinType):
scope = node.scope.find_single(ttype.name)
- elif isinstance(ttype, solnodes2.MetaTypeType):
+ elif isinstance(ttype, soltypes.MetaTypeType):
base_type = ttype.ttype
- is_interface = base_type.is_user_type() and base_type.value.x.is_interface()
- is_enum = base_type.is_user_type() and base_type.value.x.is_enum()
+ is_interface = base_type.is_user_type() and cast(solnodes2.ResolvedUserType, base_type).value.x.is_interface()
+ is_enum = base_type.is_user_type() and cast(solnodes2.ResolvedUserType, base_type).value.x.is_enum()
scope = node.scope.find_metatype(ttype.ttype, is_interface, is_enum)
else:
if use_encoded_type_key:
@@ -666,8 +782,8 @@ def scopes_for_type(self, node: solnodes1.Node, ttype: solnodes2.Type, use_encod
scopes = []
if ttype.is_address() and ttype.is_payable:
# address payable is essentially a sub type of address
- scopes.extend(node.scope.find_type(solnodes2.AddressType(False)))
- scopes.extend(node.scope.find_type(solnodes2.AddressType(True)))
+ scopes.extend(node.scope.find_type(soltypes.AddressType(False)))
+ scopes.extend(node.scope.find_type(soltypes.AddressType(True)))
else:
scopes.extend(node.scope.find_type(ttype))
return scopes
@@ -678,15 +794,20 @@ def scopes_for_type(self, node: solnodes1.Node, ttype: solnodes2.Type, use_encod
assert isinstance(scope, symtab.Scope), f'{type(scope)}'
return [scope]
- def map_type(self, ttype: Union[solnodes1.Type, solnodes2.Type]) -> solnodes2.Type:
- if isinstance(ttype, solnodes2.Type):
+ def map_type(self, ttype: soltypes.Type) -> solnodes2.Types:
+
+ if isinstance(ttype, solnodes2.Types) and not isinstance(ttype, solnodes1.Types):
+ # AST2 specific type, doesn't need checking below
return ttype
- if isinstance(ttype, solnodes1.UserType):
+ if isinstance(ttype, soltypes.UserType):
return self.get_user_type(ttype)
- elif isinstance(ttype, solnodes1.BytesType):
- return solnodes2.BytesType()
- elif isinstance(ttype, solnodes1.VariableLengthArrayType):
+ # string and bytes have to go before the base Array cases below
+ elif isinstance(ttype, soltypes.BytesType):
+ return soltypes.BytesType()
+ elif isinstance(ttype, soltypes.StringType):
+ return soltypes.StringType()
+ elif isinstance(ttype, soltypes.VariableLengthArrayType):
base_type = self.map_type(ttype.base_type)
size_type = self.get_expr_type(ttype.size)
# Fix for some weird grammar parsing issues where a fixed length array type is parsed as a variable length
@@ -696,27 +817,29 @@ def map_type(self, ttype: Union[solnodes1.Type, solnodes2.Type]) -> solnodes2.Ty
if size_type.is_int() and size_type.is_literal_type() and isinstance(ttype.size, solnodes1.Literal):
size = ttype.size.value
assert isinstance(size, int)
- return solnodes2.FixedLengthArrayType(base_type, size)
+ return soltypes.FixedLengthArrayType(base_type, size)
else:
- return solnodes2.VariableLengthArrayType(base_type, self.builder.refine_expr(ttype.size))
- elif isinstance(ttype, solnodes1.FixedLengthArrayType):
- return solnodes2.FixedLengthArrayType(self.map_type(ttype.base_type), ttype.size)
- elif isinstance(ttype, solnodes1.ArrayType):
- return solnodes2.ArrayType(self.map_type(ttype.base_type))
- elif isinstance(ttype, solnodes1.AddressType):
- return solnodes2.AddressType(ttype.is_payable)
- elif isinstance(ttype, solnodes1.ByteType):
- return solnodes2.ByteType()
- elif isinstance(ttype, solnodes1.IntType):
- return solnodes2.IntType(ttype.is_signed, ttype.size)
- elif isinstance(ttype, solnodes1.BoolType):
- return solnodes2.BoolType()
- elif isinstance(ttype, solnodes1.StringType):
- return solnodes2.StringType()
- elif isinstance(ttype, solnodes1.MappingType):
- return solnodes2.MappingType(self.map_type(ttype.src), self.map_type(ttype.dst))
- elif isinstance(ttype, solnodes1.FunctionType):
- return solnodes2.FunctionType(self.param_types(ttype.parameters), self.param_types(ttype.return_parameters))
+ return soltypes.VariableLengthArrayType(base_type, self.builder.refine_expr(ttype.size))
+ elif isinstance(ttype, soltypes.FixedLengthArrayType):
+ return soltypes.FixedLengthArrayType(self.map_type(ttype.base_type), ttype.size)
+ elif isinstance(ttype, soltypes.ArrayType):
+ return soltypes.ArrayType(self.map_type(ttype.base_type))
+ elif isinstance(ttype, soltypes.AddressType):
+ return soltypes.AddressType(ttype.is_payable)
+ elif isinstance(ttype, soltypes.ByteType):
+ return soltypes.ByteType()
+ elif isinstance(ttype, soltypes.IntType):
+ return soltypes.IntType(ttype.is_signed, ttype.size)
+ elif isinstance(ttype, soltypes.BoolType):
+ return soltypes.BoolType()
+ elif isinstance(ttype, soltypes.MappingType):
+ return soltypes.MappingType(self.map_type(ttype.src), self.map_type(ttype.dst),
+ self.builder.ident(ttype.src_name), self.builder.ident(ttype.dst_name))
+ elif isinstance(ttype, soltypes.FunctionType):
+ # TODO: fix the cases for polymorphic types where inputs or outputs is set to None
+ return soltypes.FunctionType([self.map_type(t) for t in ttype.inputs] if ttype.inputs is not None else None,
+ [self.map_type(t) for t in ttype.outputs] if ttype.outputs is not None else None,
+ self.builder.modifiers(ttype))
self.error_handler.todo(ttype)
@@ -726,7 +849,7 @@ def get_contract_type(self, user_type_symbol: symtab.Symbol) -> solnodes2.Resolv
contract = self.builder.get_synthetic_owner(user_type_symbol.source_unit_name, user_type_symbol)
else:
contract = self.builder.load_if_required(user_type_symbol)
- ttype = solnodes2.ResolvedUserType(solnodes2.Ref(contract))
+ ttype = solnodes2.ResolvedUserType(nodebase.Ref(contract))
ttype.scope = user_type_symbol
return ttype
@@ -749,7 +872,7 @@ def accept(sym: symtab.Symbol):
return accept
- def get_user_type(self, ttype: solnodes1.UserType):
+ def get_user_type(self, ttype: soltypes.UserType):
"""Maps an AST1 UserType to AST2 ResolvedUserType in the scope of the AST1 node that references the type"""
s = ttype.scope.find_user_type_scope(ttype.name.text, find_base_symbol=True)
if not s:
@@ -761,7 +884,7 @@ class Builder:
@dataclass
class State:
- current_node: solnodes1.Node
+ current_node: solnodes1.AST1Node
def __init__(self):
error_handler = ErrorHandler(create_state=Builder.State)
@@ -775,7 +898,7 @@ def __init__(self):
self.synthetic_toplevels: Dict[str, solnodes2.FileDefinition] = {}
self.normal_toplevels = []
- self.to_refine: Deque[solnodes1.SourceUnit] = deque()
+ self.to_refine: Deque[solnodes1.SourceUnit | solnodes2.FileDefinition] = deque()
self.temp_var_counter = 0
@@ -810,7 +933,7 @@ def enqueue_files(self, files: List[symtab.FileScope]):
# don't process imported symbols under this file scope
continue
n = s.value
- if not hasattr(n, 'ast2_node') and self.should_create_skeleton(n):
+ if self.should_create_skeleton(n) and not n.ast2_node:
self.define_skeleton(n, file_scope.source_unit_name)
def process_all(self):
@@ -822,7 +945,7 @@ def process_all(self):
self.refine_unit_or_part(n)
- def load_non_top_level_if_required(self, ast1_node: solnodes1.SourceUnit) -> solnodes2.ContractPart:
+ def load_non_top_level_if_required(self, ast1_node: solnodes1.SourceUnit | solnodes1.ContractPart) -> solnodes2.ContractPart:
"""
Ensures the given AST1 non top level node has been skeletoned as an AST2 node. This will
in turn skeleton any parent nodes that need to be made.
@@ -830,7 +953,7 @@ def load_non_top_level_if_required(self, ast1_node: solnodes1.SourceUnit) -> sol
For top level nodes use the load_if_required function instead
"""
- if hasattr(ast1_node, 'ast2_node'):
+ if ast1_node.ast2_node:
return ast1_node.ast2_node
if isinstance(ast1_node, (solnodes1.FunctionDefinition, solnodes1.ModifierDefinition, solnodes1.EventDefinition,
@@ -858,7 +981,7 @@ def load_if_required(self, user_type_symbol: symtab.Symbol) -> solnodes2.TopLeve
solnodes1.StructDefinition, solnodes1.LibraryDefinition, solnodes1.EnumDefinition,
solnodes1.UserValueType)):
- if hasattr(ast1_node, 'ast2_node'):
+ if ast1_node.ast2_node:
ast2_node = ast1_node.ast2_node
else:
# this starts at the parent_scope and tries to match then recurses up
@@ -870,7 +993,7 @@ def load_if_required(self, user_type_symbol: symtab.Symbol) -> solnodes2.TopLeve
# force skeleton of the whole file, filescope.value is the ast1 parts
for part in parent_scope.value:
# None = EOF
- if part is not None and self.should_create_skeleton(part) and not hasattr(part, 'ast2_node'):
+ if part is not None and self.should_create_skeleton(part) and not part.ast2_node:
# pass the source unit name here, this lets define_skeleton trigger the 'free floating'
# check if the part is not a top level node and adds the part to the FileDefinition.
# if it is a top level node, then it will define it as a top level node in AST2 and wont
@@ -880,7 +1003,7 @@ def load_if_required(self, user_type_symbol: symtab.Symbol) -> solnodes2.TopLeve
else:
# load the parent which will in turn define skeletons for its children, including the current
# ast1_node
- parent_was_loaded = hasattr(parent_scope.value, 'ast2_node')
+ parent_was_loaded = parent_scope.value.ast2_node is not None
logging.getLogger('AST2').debug(f'Loading parent of {ast1_node.name.text} ({parent_scope.aliases[0]})')
parent_type = self.load_if_required(parent_scope)
source_unit_name = f'{parent_type.source_unit_name}${parent_type.name.text}'
@@ -991,14 +1114,14 @@ def map_node(x):
# Special case of refine_function_call
error_def, new_args = self.refine_call_function(node.call, allow_error=True)
assert isinstance(error_def, solnodes2.ErrorDefinition)
- return solnodes2.RevertWithError(solnodes2.Ref(error_def), new_args)
+ return solnodes2.RevertWithError(nodebase.Ref(error_def), new_args)
self.error_handler.todo(node)
- def get_declaring_contract_scope(self, node: solnodes1.Node) -> Union[
+ def get_declaring_contract_scope(self, node: solnodes1.AST1Node) -> Union[
symtab.ContractOrInterfaceScope, symtab.LibraryScope, symtab.EnumScope, symtab.StructScope, symtab.EnumScope, symtab.FileScope]:
return self.get_declaring_contract_scope_in_scope(node.scope)
- def get_declaring_contract_scope_in_scope(self, scope: symtab.Scope) -> Union[
+ def get_declaring_contract_scope_in_scope(self, scope: symtab.Symbol) -> Union[
symtab.ContractOrInterfaceScope, symtab.LibraryScope, symtab.EnumScope, symtab.StructScope, symtab.EnumScope, symtab.FileScope]:
return scope.find_first_ancestor_of((symtab.ContractOrInterfaceScope, symtab.LibraryScope,
symtab.EnumScope, symtab.StructScope, symtab.EnumScope,
@@ -1017,7 +1140,7 @@ def get_super_object(self, node: Union[solnodes1.Stmt, solnodes1.Expr]):
@dataclass
class FunctionCallee:
- base: Union[solnodes2.Expr, symtab.Symbol]
+ base: Optional[solnodes2.Expr | symtab.Symbol]
symbols: List[symtab.Symbol]
@dataclass
@@ -1038,7 +1161,7 @@ def create_new_args():
return results
def create_option_args():
- return [solnodes2.NamedArgument(solnodes2.Ident(arg.name), self.refine_expr(arg.value)) for arg in expr.modifiers]
+ return [solnodes2.NamedArgument(self.ident(arg.name), self.refine_expr(arg.value)) for arg in expr.modifiers]
callee = expr.callee
@@ -1098,7 +1221,7 @@ def create_option_args():
def is_type_call(s):
value = s.res_syms_single().value
# type calls when X in X(a) is a type, e.g. MyContract(_addr), bytes(xx), etc, which are casts
- return isinstance(value, (solnodes1.Type, solnodes2.Type)) or self.is_top_level(value)
+ return isinstance(value, soltypes.Type) or self.is_top_level(value)
type_calls = [is_type_call(symbol) for c in callees for symbol in c.symbols]
# can't have ambiguity for casts, so if one of the matches is a cast then they must all be (and there must only
@@ -1116,7 +1239,7 @@ def is_type_call(s):
self.error_handler.assert_error(f'Bucket matches to multiple types: {res_syms}', len(res_syms) == 1)
ttype = self.type_helper.symbol_to_ast2_type(callees[0].symbols[0])
- if ttype.is_user_type() and ttype.value.x.is_struct():
+ if ttype.is_user_type() and cast(solnodes2.ResolvedUserType, ttype).value.x.is_struct():
# struct init
new_args = create_new_args()
self.error_handler.error(f'Option args not allowed during struct initialiser: {option_args}',
@@ -1136,23 +1259,24 @@ def is_type_call(s):
arg_type = self.type_helper.get_expr_type(expr.args[0])
if ttype.is_address() and arg_type.is_int() and not arg_type.is_signed and arg_type.size == 160:
- ttype = solnodes2.AddressType(is_payable=True)
+ ttype = soltypes.AddressType(is_payable=True)
return solnodes2.Cast(ttype, self.refine_expr(expr.args[0]))
# match function call candidates via parameters
# (matched symbol, symbol type, is_synthetic)
- candidates = []
+ candidates: list[tuple[symtab.Symbol | solnodes2.Expr, symtab.Symbol, soltypes.Type, bool]] = []
for c in callees:
# Match the callees in the current bucket
- bucket_candidates = []
+ bucket_candidates: list[tuple[symtab.Symbol, solnodes2.Types, bool]] = []
for s in c.symbols:
# DONT pass function_callee=True here, this will give us the real type of the symbol for statevars
# i.e. we'll get uint instead of () -> uint which we need to set is_synthetic
- t = self.type_helper.symbol_to_ast2_type(s)
+ t: soltypes.Type = self.type_helper.symbol_to_ast2_type(s)
is_synthetic = False
if t.is_function():
+ t: soltypes.FunctionType
# None is a sentinel, do NOT do 'if ft.inputs:'
if t.inputs is None:
# input types == None => polymorphic builtin function. This isn't the same as a no arg function,
@@ -1163,6 +1287,7 @@ def is_type_call(s):
# match input types
input_types = t.inputs
elif t.is_mapping():
+ t: soltypes.MappingType
# MappingType, these can look like function calls but are mapping loads. A mapping type can be
# nested, like myMapping :: (x => (y => z))
flattened_types = t.flatten()
@@ -1172,7 +1297,7 @@ def is_type_call(s):
len(flattened_types) == len(arg_types) + 1)
input_types = flattened_types[:-1]
elif t.is_array() and not t.is_byte_array_underlying():
- input_types = [solnodes2.UIntType()]
+ input_types = [soltypes.UIntType()]
else:
self.error_handler.assert_error(f'Unhandled call to {type(s.value)}', isinstance(s.value, (
solnodes1.StateVariableDeclaration, solnodes1.ConstantVariableDeclaration)))
@@ -1199,11 +1324,11 @@ def is_type_call(s):
if are_sub_contracts:
aliases = ', '.join([s.aliases[0] for s in symbol_sources])
logging.getLogger('AST2').debug(f'Base chain: {aliases} @ {expr.location}')
- candidates.append((c.base, *bucket_candidates[0]))
+ candidates.append((c.base, *bucket_candidates[0])) # type: ignore
else:
return self.error_handler.assert_error(f'Resolved to too many different bases: {bucket_candidates}, args={arg_types}')
elif len(bucket_candidates) == 1:
- candidates.append((c.base, *bucket_candidates[0]))
+ candidates.append((c.base, *bucket_candidates[0])) # type: ignore
if len(candidates) == 0:
# no resolved callees
@@ -1220,33 +1345,36 @@ def is_type_call(s):
if ftype.is_mapping():
# for mapping types, the dst is the output type
- out_type = ftype.dst
- elif ftype.is_array() and not t.is_byte_array_underlying():
- out_type = ftype.base_type
+ out_type = cast(soltypes.MappingType, ftype).dst
+ elif ftype.is_array() and not ftype.is_byte_array_underlying():
+ out_type = cast(soltypes.ArrayType, ftype).base_type
elif is_synthetic:
# for synthetic candidate, the type itself is the output type
out_type = ftype
- elif ftype.outputs is None:
- # for FunctionTypes where output IS None, return type is polymorphic. So far it's only abi.decode
- if sym.aliases[0] == 'decode' and sym.parent_scope.aliases[0] == 'abi':
- self.error_handler.error(f'Invalid args: abi.decode({arg_types})', len(arg_types) == 2)
- out_type = arg_types[1]
- else:
- self.error_handler.todo(expr)
- elif len(ftype.outputs) > 1:
- # returns multiple things, set the return type as a TupleType
- out_type = solnodes2.TupleType(ftype.outputs)
- elif len(ftype.outputs) == 1:
- # one return type
- out_type = ftype.outputs[0]
else:
- # void return
- out_type = solnodes2.VoidType()
+ ftype: soltypes.FunctionType
+
+ if ftype.outputs is None:
+ # for FunctionTypes where output IS None, return type is polymorphic. So far it's only abi.decode
+ if sym.aliases[0] == 'decode' and sym.parent_scope.aliases[0] == 'abi':
+ self.error_handler.error(f'Invalid args: abi.decode({arg_types})', len(arg_types) == 2)
+ out_type = arg_types[1]
+ else:
+ return self.error_handler.todo(expr)
+ elif len(ftype.outputs) > 1:
+ # returns multiple things, set the return type as a TupleType
+ out_type = soltypes.TupleType(ftype.outputs)
+ elif len(ftype.outputs) == 1:
+ # one return type
+ out_type = ftype.outputs[0]
+ else:
+ # void return
+ out_type = soltypes.VoidType()
new_args = create_new_args()
if isinstance(sym, symtab.BuiltinFunction):
- if isinstance(possible_base, solnodes2.BuiltinType) or not possible_base:
+ if isinstance(possible_base, soltypes.BuiltinType) or not possible_base:
# TODO: separate node for revert, require, etc
if sym.aliases[0] == 'require':
assert allow_stmt
@@ -1271,8 +1399,9 @@ def is_type_call(s):
elif isinstance(possible_base, solnodes2.Expr):
# e.g. myaddress.call(...)
return solnodes2.DynamicBuiltInCall(option_args, new_args, out_type, possible_base, sym.aliases[0])
- elif isinstance(possible_base, solnodes2.Type):
- if possible_base.is_user_type() and possible_base.value.x.is_udvt():
+ elif isinstance(possible_base, solnodes2.Types):
+ possible_base: solnodes2.Types
+ if possible_base.is_user_type() and cast(solnodes2.ResolvedUserType, possible_base).value.x.is_udvt():
self.error_handler.assert_error(f'Builtin call with {possible_base} base must be a UDVT call', possible_base.value.x.is_udvt())
return solnodes2.DynamicBuiltInCall(option_args, new_args, out_type, possible_base, sym.aliases[0])
else:
@@ -1323,6 +1452,9 @@ def is_type_call(s):
# we need to set the base to a state var load or we lose information about x
expr_base = solnodes2.StateVarLoad(possible_base, solnodes2.Ident(sym.value.name.text))
+ self.error_handler.assert_error(f'No args', len(new_args) > 0)
+ new_expr = None
+
for expr_key in new_args:
new_expr = solnodes2.MappingLoad(expr_base, expr_key)
expr_base = new_expr
@@ -1351,7 +1483,7 @@ def is_type_call(s):
self.error_handler.assert_error(f'Event reference must be have no base, type base or be local: {is_local_call}/{possible_base}', (not possible_base or isinstance(possible_base, solnodes2.ResolvedUserType)) or is_local_call)
- return solnodes2.EmitEvent(solnodes2.Ref(sym.value.ast2_node), new_args)
+ return solnodes2.EmitEvent(nodebase.Ref(sym.value.ast2_node), new_args)
elif isinstance(sym.value, (solnodes1.Var, solnodes1.Parameter)):
# refine_expr again but this time not as a function callee to get the callee as an expr
return solnodes2.FunctionPointerCall(option_args, new_args, self.refine_expr(callee))
@@ -1390,8 +1522,8 @@ def is_subcontract(self, a: symtab.Scope, b: symtab.Scope):
return False
- def find_bound_operator_symbol(self, expr: Union[solnodes1.UnaryOp, solnodes1.BinaryOp],
- input_types: List[solnodes2.Type]):
+ def find_bound_operator_symbol(self, expr: solnodes1.UnaryOp | solnodes1.BinaryOp,
+ input_types: list[solnodes2.Types]):
# atm these operators are left associative for binary operators and both input types must match, just use the
# first type arbitrarily
udvt_scopes = self.type_helper.scopes_for_type(expr, input_types[0])
@@ -1417,11 +1549,12 @@ def refine_bound_operator(self, expr: Union[solnodes1.UnaryOp, solnodes1.BinaryO
input_types = [a.type_of() for a in inputs]
function_symbol = self.find_bound_operator_symbol(expr, input_types)
ast1_function = function_symbol.value
- binding_f: solnodes2.FunctionDefinition = self.load_non_top_level_if_required(ast1_function)
+ # ast1 function will always map to an ast2 function
+ binding_f = cast(solnodes2.FunctionDefinition, self.load_non_top_level_if_required(ast1_function))
arg_types = [p.var.ttype for p in binding_f.inputs]
# currently only matching types are allowed (no implicit casts)
self.error_handler.assert_error(f'Mismatched arg types: {arg_types} vs {input_types}', arg_types == input_types)
- return solnodes2.DirectCall([], inputs, binding_f.parent.as_type(),
+ return solnodes2.DirectCall([], inputs, cast(solnodes2.TopLevelUnit, binding_f.parent).as_type(),
solnodes2.Ident(binding_f.name.text))
def get_function_call_symbol_base(self, s: symtab.Symbol):
@@ -1503,7 +1636,7 @@ def make_assign(lhs, rhs, is_array_length_minus=False):
self.temp_var_counter += 1
def z():
- return solnodes2.Var(solnodes2.Ident(var_name), solnodes2.TupleType(ttypes), None)
+ return solnodes2.Var(solnodes2.Ident(var_name), soltypes.TupleType(ttypes), None)
# Note this does break up the scoping as defined in the symtab but it's very difficult to correct it
# and not worth it imo as after this AST2 pass the symtab is embedded naturally in the AST so doesn't
@@ -1535,11 +1668,13 @@ def z():
return make_assign(left, value, is_array_length_minus)
else:
return solnodes2.BinaryOp(left, right, expr.op)
- elif isinstance(expr, solnodes1.Type):
+ elif isinstance(expr, solnodes1.Types):
+ expr: solnodes1.Types
if is_function_callee:
# E.g. calls that look like T(x) (Casts)
# Type as expr has no base (direct reference)
- return [Builder.FunctionCallee(None, expr.scope.find_type(expr, as_single=False))]
+ zs = expr.scope.find_type(expr, as_single=False)
+ return [Builder.FunctionCallee(None, zs)]
elif is_argument:
# for arguments, types can sometimes be passed, e.g. abi.decode(x, bool)
return solnodes2.TypeLiteral(self.type_helper.map_type(expr))
@@ -1565,7 +1700,7 @@ def z():
if is_function_callee:
if expr.text == 'address':
# weird grammar edge case where it's parsed as an ident instead of a type
- ttype = solnodes1.AddressType(is_payable=False)
+ ttype = soltypes.AddressType(is_payable=False)
# FIXME: surely this is always true?
if is_function_callee:
@@ -1617,7 +1752,7 @@ def z():
if isinstance(ident_target, solnodes1.FunctionDefinition):
# TODO: can this be ambiguous or does the reference always select a single function
- return solnodes2.GetFunctionPointer(solnodes2.Ref(ident_target.ast2_node))
+ return solnodes2.GetFunctionPointer(nodebase.Ref(ident_target.ast2_node))
elif isinstance(ident_target, solnodes1.ConstantVariableDeclaration):
base_scope = self.get_declaring_contract_scope(ident_target)
base_type = self.type_helper.get_contract_type(base_scope)
@@ -1660,10 +1795,10 @@ def z():
base = expr.obj_base
mname = expr.name.text
- base_type: solnodes2.Type = self.type_helper.get_expr_type(expr.obj_base)
+ base_type: solnodes2.Types = self.type_helper.get_expr_type(expr.obj_base)
- if not isinstance(base_type, solnodes2.FunctionType) or is_function_callee:
- find_direct_scope = isinstance(base, (solnodes1.BytesType, solnodes1.StringType))
+ if not isinstance(base_type, soltypes.FunctionType) or is_function_callee:
+ find_direct_scope = isinstance(base, (soltypes.BytesType, soltypes.StringType))
base_scopes = self.type_helper.scopes_for_type(base, base_type, use_encoded_type_key=not find_direct_scope)
using_predicate = self.type_helper.create_filter_using_scope(base_type)
@@ -1675,7 +1810,7 @@ def z():
assert len(member_symbols) > 0, f'No matches to call {str(base)}.{mname}'
if is_function_callee:
- if isinstance(base_type, solnodes2.BuiltinType):
+ if isinstance(base_type, soltypes.BuiltinType):
bucket_base = base_type
else:
bucket_base = self.refine_expr(base, allow_type=True)
@@ -1706,7 +1841,7 @@ def z():
are_sub_contracts)
func_sym = member_symbols[0][0]
if isinstance(func_sym.value, solnodes1.FunctionDefinition):
- return solnodes2.GetFunctionPointer(solnodes2.Ref(func_sym.value.ast2_node))
+ return solnodes2.GetFunctionPointer(nodebase.Ref(func_sym.value.ast2_node))
# if sum(len(xs) for xs in member_symbols) > 1:
# logging.getLogger('AST2').info(
@@ -1720,7 +1855,7 @@ def z():
sym = unique_member_symbols[0]
if isinstance(sym, symtab.BuiltinValue):
- if isinstance(base_type, solnodes2.BuiltinType):
+ if isinstance(base_type, soltypes.BuiltinType):
# e.g. msg.gas, where the base is a builtin object
return solnodes2.GlobalValue(f'{base_type.name}.{mname}', self.type_helper.map_type(sym.ttype))
else:
@@ -1731,7 +1866,7 @@ def z():
input_params = [solnodes2.Parameter(solnodes2.Var(None, self.type_helper.map_type(t), None)) for t in (sym.input_types or [])]
output_params = [solnodes2.Parameter(solnodes2.Var(None, self.type_helper.map_type(t), None)) for t in (sym.output_types or [])]
builtin_f = solnodes2.BuiltinFunction(sym.aliases[0], input_params, output_params)
- return solnodes2.GetFunctionPointer(solnodes2.Ref(builtin_f))
+ return solnodes2.GetFunctionPointer(nodebase.Ref(builtin_f))
else:
referenced_member = sym.value
new_base = self.refine_expr(base, allow_type=True)
@@ -1743,9 +1878,9 @@ def z():
# if the base is a type, it's a constant load, i.e. MyX.myConst (possibly also a qualified
# lookup like MyX.MyY.myConst?)
# else it's an instance member load which requires an expr base
- if isinstance(new_base, solnodes2.Type):
+ if isinstance(new_base, solnodes2.Types):
assert isinstance(new_base, solnodes2.ResolvedUserType)
- assert solnodes1.MutabilityModifierKind.CONSTANT in [m.kind for m in referenced_member.modifiers]
+ assert solnodes1.MutabilityModifierKind.CONSTANT in [m.kind for m in referenced_member.modifiers if hasattr(m, 'kind')]
return solnodes2.StaticVarLoad(new_base, solnodes2.Ident(referenced_member.name.text))
elif isinstance(referenced_member, solnodes1.Ident) and isinstance(referenced_member.parent,
solnodes1.EnumDefinition):
@@ -1753,7 +1888,7 @@ def z():
member_matches = [member for member in new_base.value.x.values
if member.name.text == referenced_member.text]
assert len(member_matches) == 1
- return solnodes2.EnumLoad(solnodes2.Ref(member_matches[0]))
+ return solnodes2.EnumLoad(nodebase.Ref(member_matches[0]))
elif self.is_top_level(referenced_member) or isinstance(referenced_member, solnodes1.ErrorDefinition):
assert isinstance(new_base, solnodes2.ResolvedUserType)
# Qualified top level reference, e.g. MyLib.MyEnum...
@@ -1785,7 +1920,7 @@ def z():
possible_base = callee.base
# TODO: make this work without explicit check
if mname == 'selector':
- return solnodes2.ABISelector(solnodes2.Ref(member_symbol.value.ast2_node))
+ return solnodes2.ABISelector(nodebase.Ref(member_symbol.value.ast2_node))
else:
# the named arg value comes as the argument of the parent call function expr
return [Builder.PartialFunctionCallee(possible_base, [member_symbol], { mname: None })]
@@ -1800,14 +1935,14 @@ def z():
assert not expr.unit
type_args = [self.type_helper.map_as_type_arg(arg) for arg in expr.value]
- are_type_args = [isinstance(arg, (solnodes1.Type, solnodes2.Type)) for arg in type_args]
+ are_type_args = [isinstance(arg, soltypes.Type) for arg in type_args]
assert TypeHelper.any_or_all(are_type_args)
if any(are_type_args):
# the grammar has 'TupleExpression' s, e.g. '(' exprList ')'. The exprs it allows can also be types.
# Either all or none of the exprs must be types
# but the parser is weird
- return solnodes2.TypeLiteral(solnodes2.TupleType([self.type_helper.map_type(t) for t in type_args]))
+ return solnodes2.TypeLiteral(soltypes.TupleType([self.type_helper.map_type(t) for t in type_args]))
elif len(expr.value) == 1:
# Bracketed expressions, not tuples, e.g. (x).y() , (x) isn't a tuple so unpack here
assert isinstance(expr.value[0], solnodes1.Expr)
@@ -1825,8 +1960,8 @@ def z():
if is_argument or allow_tuple_exprs:
return [self.refine_expr(e, is_assign_rhs=is_assign_rhs) for e in expr.value]
self.error_handler.todo(expr)
- elif isinstance(expr.value, solnodes1.Type):
- self.error_handler.todo(expr)
+ # elif isinstance(expr.value, solnodes1.Type):
+ # self.error_handler.todo(expr)
else:
assert not isinstance(expr.value, solnodes1.Expr)
# if this value determines the RHS of something with an expected type, e.g. bytes myb = 1234567...;
@@ -1837,7 +1972,7 @@ def z():
elif isinstance(expr, solnodes1.GetArrayValue):
if allow_type:
possible_type = self.type_helper.map_as_type_arg(expr)
- if possible_type and isinstance(possible_type, solnodes2.Type):
+ if possible_type and isinstance(possible_type, solnodes2.Types):
return possible_type
return solnodes2.ArrayLoad(self.refine_expr(expr.array_base), self.refine_expr(expr.index))
elif isinstance(expr, solnodes1.GetArraySlice):
@@ -1846,21 +1981,21 @@ def z():
elif isinstance(expr, solnodes1.PayableConversion):
# address payable cast
assert len(expr.args) == 1
- return solnodes2.Cast(solnodes2.AddressType(True), self.refine_expr(expr.args[0]))
+ return solnodes2.Cast(soltypes.AddressType(True), self.refine_expr(expr.args[0]))
elif isinstance(expr, solnodes1.CreateMetaType):
return solnodes2.GetType(self.type_helper.map_type(expr.base_type))
elif isinstance(expr, solnodes1.TernaryOp):
return solnodes2.TernaryOp(self.refine_expr(expr.condition), self.refine_expr(expr.left, allow_tuple_exprs=allow_tuple_exprs), self.refine_expr(expr.right, allow_tuple_exprs=allow_tuple_exprs))
elif isinstance(expr, solnodes1.NamedArg):
- return solnodes2.NamedArgument(solnodes2.Ident(expr.name.text), self.refine_expr(expr.value))
+ return solnodes2.NamedArgument(self.ident(expr.name), self.refine_expr(expr.value))
elif isinstance(expr, solnodes1.NewInlineArray):
return solnodes2.CreateInlineArray([self.refine_expr(e) for e in expr.elements])
self.error_handler.todo(expr)
- def find_method(self, possible_matches: List[symtab.Symbol], arg_types: List[solnodes2.Type]):
+ def find_method(self, possible_matches: list[symtab.Symbol], arg_types: list[solnodes2.Types]):
assert not any([x is None for x in arg_types])
- def get_arg_types(func_scope: symtab.ModFunErrEvtScope) -> List[solnodes2.Type]:
+ def get_arg_types(func_scope: symtab.ModFunErrEvtScope) -> list[solnodes2.Types]:
assert isinstance(func_scope, symtab.ModFunErrEvtScope)
return [self.type_helper.map_type(p.var_type) for p in func_scope.value.parameters]
@@ -1882,7 +2017,7 @@ def check_arg_types(s: symtab.Symbol) -> bool:
target_param_types = get_arg_types(s)
actual_param_types = arg_types
- return solnodes2.Type.are_matching_types(target_param_types, actual_param_types)
+ return soltypes.Type.are_matching_types(target_param_types, actual_param_types)
actual_matches = [x for x in possible_matches if check_arg_types(x)]
@@ -1916,6 +2051,14 @@ def error_parameter(self, node: solnodes1.ErrorParameter):
name = solnodes2.Ident(node.name.text if node.name else None)
return solnodes2.ErrorParameter(self.type_helper.map_type(node.var_type), name)
+ def ident(self, node: solnodes1.Ident):
+ return solnodes2.Ident(node.text) if node else None
+
+ def modifiers(self, node_with_modifiers):
+ if not hasattr(node_with_modifiers, 'modifiers'):
+ return []
+ return [self.modifier(m) for m in node_with_modifiers.modifiers]
+
def modifier(self, node: solnodes1.Modifier):
if isinstance(node, solnodes1.VisibilityModifier2):
return solnodes2.VisibilityModifier(node.kind)
@@ -1947,8 +2090,8 @@ def modifier(self, node: solnodes1.Modifier):
target = self.load_non_top_level_if_required(mod_defs[0].value)
node_klass = solnodes2.FunctionInvocationModifier
else:
- self.error_handler.todo(node)
- return node_klass(target, [self.refine_expr(e) for e in node.arguments] if node.arguments else [])
+ return self.error_handler.todo(node)
+ return node_klass(target, [self.refine_expr(e) for e in node.arguments] if node.arguments else []) # type: ignore
self.error_handler.todo(node)
@@ -1983,7 +2126,7 @@ def get_synthetic_owner(self, source_unit_name, file_scope: symtab.FileScope) ->
self.synthetic_toplevels[source_unit_name] = toplevel
return toplevel
- def define_skeleton(self, ast1_node: solnodes1.SourceUnit, source_unit_name: str) -> solnodes2.TopLevelUnit:
+ def define_skeleton(self, ast1_node: solnodes1.SourceUnit, source_unit_name: Optional[str]) -> solnodes2.TopLevelUnit | solnodes2.ContractPart:
assert self.should_create_skeleton(ast1_node), f'{type(ast1_node)}'
"""
Makes a skeleton of the given AST1 node without processing the details. This is required as user types are
@@ -2005,11 +2148,10 @@ def define_skeleton(self, ast1_node: solnodes1.SourceUnit, source_unit_name: str
If the SUN is not set, the node is a child of another top level unit(not directly the child of a FileScope),
e.g. a function defined in a contract.
"""
-
- assert not hasattr(ast1_node, 'ast2_node')
+ assert not ast1_node.ast2_node
logging_f = logging.getLogger('AST2').debug
- logging_f(f' making skeleton for {type(ast1_node).__name__}({ast1_node.name}) :: {source_unit_name}')
+ logging_f(f' making skeleton for {type(ast1_node).__name__}({ast1_node.name}) :: {source_unit_name}') # type: ignore
# Source unit name is only used for source units/top level units
# This is the case where we have functions, errors, event, constants that are defined outside of a top level
@@ -2095,7 +2237,7 @@ def _make_new_node(n):
for p in ast1_node.parts:
# don't need usings or pragmas for AST2
- if not self.is_top_level(p) and self.should_create_skeleton(p) and not hasattr(p, 'ast2_node'):
+ if not self.is_top_level(p) and self.should_create_skeleton(p) and not p.ast2_node:
ast2_node.parts.append(self.define_skeleton(p, None))
if isinstance(p, (solnodes1.StateVariableDeclaration, solnodes1.ConstantVariableDeclaration)):
@@ -2195,7 +2337,7 @@ def refine_unit_or_part(self, ast1_node: Union[solnodes1.SourceUnit, solnodes2.F
library_scope = part.scope.find_user_type_scope(part.library_name.text, find_base_symbol=True)
assert isinstance(library_scope.value, solnodes1.LibraryDefinition)
library = self.type_helper.get_contract_type(library_scope)
- if isinstance(part.override_type, solnodes1.AnyType):
+ if isinstance(part.override_type, soltypes.AnyType):
for sym in library_scope.get_all_functions():
input_params = sym.value.parameters
if input_params:
@@ -2211,7 +2353,7 @@ def refine_unit_or_part(self, ast1_node: Union[solnodes1.SourceUnit, solnodes2.F
pass
part_ast1node = None
- if hasattr(part, 'ast2_node'):
+ if hasattr(part, 'ast2_node') and part.ast2_node:
part_ast1node = part
elif hasattr(part, 'is_free') and part.is_free:
part_ast1node = part.ast1_node
@@ -2249,9 +2391,9 @@ def refine_node(n):
refine_node(ast2_node)
return None
- def is_top_level(self, node: solnodes1.Node):
+ def is_top_level(self, node: solnodes1.AST1Node):
# Error and FunctionDefinitions are set as SourceUnits in AST1 but not in AST2
return isinstance(node, solnodes1.SourceUnit) and not isinstance(node, (solnodes1.ImportDirective, solnodes1.FunctionDefinition, solnodes1.ErrorDefinition, solnodes1.StateVariableDeclaration, solnodes1.ConstantVariableDeclaration))
- def should_create_skeleton(self, node: solnodes1.Node) -> bool:
+ def should_create_skeleton(self, node: solnodes1.AST1Node) -> bool:
return isinstance(node, (solnodes1.SourceUnit, solnodes1.ContractPart)) and not isinstance(node, (solnodes1.ImportDirective, solnodes1.PragmaDirective, solnodes1.UsingDirective))
diff --git a/src/solidity_parser/ast/funcanalysis.py b/src/solidity_parser/ast/funcanalysis.py
index 712c734..f21cf3f 100644
--- a/src/solidity_parser/ast/funcanalysis.py
+++ b/src/solidity_parser/ast/funcanalysis.py
@@ -3,8 +3,9 @@
from enum import Enum
from solidity_parser.ast.solnodes2 import (FunctionCall, DirectCall, ResolvedUserType, TopLevelUnit, FunctionDefinition,
- Type, SuperType, Node, SuperObject, SelfObject, UnprocessedCode, Stmt,
+ SuperType, AST2Node, SuperObject, SelfObject, UnprocessedCode, Stmt,
Assembly)
+from solidity_parser.ast.types import Type
from solidity_parser.ast.mro_helper import c3_linearise
from solidity_parser.ast.solnodes import VisibilityModifierKind, MutabilityModifierKind
diff --git a/src/solidity_parser/ast/hierarchy.py b/src/solidity_parser/ast/hierarchy.py
index af64260..0526a13 100644
--- a/src/solidity_parser/ast/hierarchy.py
+++ b/src/solidity_parser/ast/hierarchy.py
@@ -1,8 +1,11 @@
-from typing import List
-from solidity_parser.ast.solnodes2 import Ref, TopLevelUnit
+from solidity_parser.ast.nodebase import Ref
+from solidity_parser.ast.solnodes2 import TopLevelUnit
-def build_hierarchy(top_level_units: List[TopLevelUnit]):
+def build_hierarchy(top_level_units: list[TopLevelUnit]) -> None:
+ """
+ Annotates the top level units with their direct subtypes, e.g. if A extends B, then A._subtypes = [B]
+ """
for u in top_level_units:
supers = u.get_supers()
for s in supers:
diff --git a/src/solidity_parser/ast/mro_helper.py b/src/solidity_parser/ast/mro_helper.py
index cecd385..a1200db 100644
--- a/src/solidity_parser/ast/mro_helper.py
+++ b/src/solidity_parser/ast/mro_helper.py
@@ -1,4 +1,4 @@
-from typing import List
+from typing import TypeVar, Callable
def _merge(*sequences):
@@ -27,15 +27,27 @@ def _merge(*sequences):
del seq[0]
-def c3_linearise(klass, get_supers=None):
+T = TypeVar('T')
+
+
+def c3_linearise(klass: T, get_supers: Callable[[T], list[T]] = None) -> list[T]:
+ """
+ A function to linearise the class hierarchy using the C3 linearisation algorithm.
+
+ :param klass: The class to linearise.
+ :param get_supers: A function to get the superclasses of a given class, must return a list of classes with the same
+ type as the input
+ :return: A linearised list of classes following the C3 algorithm.
+ """
+
if get_supers is not None:
- superklasses = get_supers(klass)
+ superclasses = get_supers(klass)
else:
- superklasses = klass.get_supers()
+ superclasses = klass.get_supers()
# In solidity this is reversed for some reason
- superklasses = list(reversed(superklasses))
- if not superklasses:
+ superclasses = list(reversed(superclasses))
+ if not superclasses:
return [klass]
else:
- return [klass] + _merge(*[c3_linearise(k, get_supers) for k in superklasses], superklasses)
+ return [klass] + _merge(*[c3_linearise(k, get_supers) for k in superclasses], superclasses)
diff --git a/src/solidity_parser/ast/nodebase.py b/src/solidity_parser/ast/nodebase.py
new file mode 100644
index 0000000..71bf360
--- /dev/null
+++ b/src/solidity_parser/ast/nodebase.py
@@ -0,0 +1,319 @@
+from dataclasses import dataclass, field
+from typing import TypeVar, NamedTuple, Optional, Generic, Callable, Generator
+from copy import deepcopy
+
+
+class SourceLocation(NamedTuple):
+ line: int
+ "Line number, beginning at 1"
+ column: int
+ "Column number, beginning at 1. E.g. the first character on the line is at column 1."
+
+
+class SourceLocationSpan(NamedTuple):
+ start: SourceLocation
+ end: SourceLocation
+
+ def does_contain(self, loc: SourceLocation):
+ """
+ Checks whether the given 'loc' location is contained within this span.
+ E.g. if this span represents ((5,1), (10, 1)), i.e lines 5 to 10 and loc is (6, 1), the location is contained
+ :param loc:
+ :return:
+ """
+
+ if loc.line < self.start.line or loc.line > self.end.line:
+ # outside the line range
+ return False
+
+ # below: the location is in the line range
+
+ before_start, after_end = loc.column < self.start.column, loc.column > self.end.column
+ on_start_line, on_end_line = loc.line == self.start.line, loc.line == self.end.line
+
+ if on_start_line and on_end_line:
+ # i.e. start and end line are the same, check within column range
+ return not (before_start or after_end)
+ elif on_start_line:
+ # on the start line (not on the end line, end line != start line), check after the start col
+ return not before_start
+ elif on_end_line:
+ # above but for end line
+ return not after_end
+ else:
+ # start and end lines are not the same and the loc is somewhere between, but not on the start or end lines
+ return True
+
+
+__REASON_CHILD__ = '__child__'
+__FIELD_PARENT__ = 'parent'
+__REASON_INIT__ = '__init__'
+
+
+def NodeDataclass(cls, *args, **kwargs):
+ """
+ AST node decorator to add an updatable and cachable element based hash to the dataclass
+ """
+
+ # Add a hash based on the elements that make up this node. This is required because dataclass doesn't generate a
+ # hash for us unless we pass in unsafe_hash=True on the decorator for every node subclass and even if we do that
+ # it can't hash lists. Since get_all_children returns a generator of nodes (i.e. no lists), we can hash it as a
+ # tuple, i.e. a "snapshot hash"
+ def compute_node_hash(self):
+ return hash(tuple(self.get_all_children()))
+
+ def __hash__(self):
+ if not self._cached_hash:
+ # this hash can be computed many times if the dataclass field that made this instance dirty is not a real
+ # child, i.e. doesn't get returned in get_children() because its not a Node(e.g. the field is a List[str])
+ # For now just allow this because we'd have to recurse on the object to see if it really makes a difference
+ # to the hash, and it's not worth it
+ self._cached_hash = self.compute_node_hash()
+ return self._cached_hash
+
+ actual_dataclass = dataclass(cls, *args, **kwargs)
+
+ actual_init = actual_dataclass.__init__
+ actual_setattr = actual_dataclass.__setattr__
+
+ def __setattr__(self, name, value):
+ # wrap lists as they are mutable in our own list type that can notify when elements are changed
+ # since NodeList is also a list, this will take the existing nodelist and wrap it
+ if isinstance(value, list):
+ value = NodeList(self, value)
+
+ actual_setattr(self, name, value)
+ # if this attribute was declared as a dataclass field, the state of this node is dirty as the
+ # contents changed
+ if name in actual_dataclass.__dataclass_fields__:
+ self._set_dirty(name, value)
+
+ def _set_dirty(self, name, value):
+ # in the case of lists, name can be an int or slice
+
+ # a node is considered hash dirty if its direct children or grandchildren attributes are changed
+ # - if the parent of a node is changed, the node does not become hash dirty
+ # __FIELD_PARENT__ is triggered when the parent is changed
+ # __REASON_CHILD__ is not a real attribute, it's triggered to alert the parent of this node that the child was
+ # made hash dirty(e.g. because of a grandchild becoming hash dirty)
+ # final case is for real attributes in this node that were just changed
+ if name != __FIELD_PARENT__ or name == __REASON_CHILD__:
+ # print("HashDirty: " + str(id(self))[9:] +" because of " + str(name))
+ self._cached_hash = None
+ if self.parent:
+ # parent is recursively dirty
+ self.parent._set_dirty(__REASON_CHILD__, self)
+
+ def __init__(self, *args, **kwargs):
+ actual_init(self, *args, **kwargs)
+ self._cached_hash = None
+
+ actual_dataclass.__hash__ = __hash__
+ actual_dataclass.compute_node_hash = compute_node_hash
+ actual_dataclass.__setattr__ = __setattr__
+ actual_dataclass.__init__ = __init__
+ actual_dataclass._set_dirty = _set_dirty
+
+ return actual_dataclass
+
+
+T = TypeVar('T')
+
+
+@NodeDataclass
+class NodeList(list[T]):
+ # Note: this class is marked as a NodeDataclass and has _set_dirty defined by the decorator. Ignore IDE warnings
+ def __init__(self, parent: T, seq=()):
+ super().__init__(seq)
+ self.parent = parent
+
+ def __str__(self):
+ return list.__str__(self)
+
+ def __repr__(self):
+ return list.__repr__(self)
+
+ def __setitem__(self, key, value):
+ # seems to get called with slices too, that's why __setslice__ is stubbed with TODO
+ super().__setitem__(key, value)
+ self._set_dirty(key, value)
+
+ def __delitem__(self, key):
+ super().__delitem__(key)
+ self._set_dirty(key, None)
+
+ def __setslice__(self, i, j, sequence):
+ raise NotImplemented
+
+ def __eq__(self, other):
+ if isinstance(other, list):
+ return super().__eq__(other)
+ raise NotImplemented
+
+ def append(self, __object):
+ ret = super().append(__object)
+ self._set_dirty('__append__', __object)
+ return ret
+
+ def clear(self):
+ ret = super().clear()
+ self._set_dirty('__clear__', None)
+ return ret
+
+ def extend(self, __iterable):
+ ret = super().extend(__iterable)
+ self._set_dirty('__extend__', None)
+ return ret
+
+ def insert(self, __index, __object):
+ ret = super().insert(__index, __object)
+ self._set_dirty('__insert__', __object)
+ return ret
+
+ def pop(self, __index):
+ ret = super().pop(__index)
+ self._set_dirty('__pop__', None)
+ return ret
+
+ def remove(self, __value):
+ ret = super().remove(__value)
+ self._set_dirty('__remove__', None)
+ return ret
+
+ def reverse(self):
+ ret = super().reverse()
+ self._set_dirty('__reverse__', None)
+ return ret
+
+ def sort(self, *args, **kwargs):
+ ret = super().sort(*args, **kwargs)
+ self._set_dirty('__sort__', None)
+ return ret
+
+
+@dataclass
+class Ref(Generic[T]):
+ """
+ A weak AST reference to another Node. This is needed when we want to associate a Node with another Node but don't
+ want it to be marked as a child of the other Node. This is useful if we want to create circular or back references
+ to help the client use the AST more naturally, e.g. ResolvedUserTypes have a reference to the actual TopLevelUnit
+ they reference.
+ """
+
+ x: T
+ "The item being referenced"
+
+ def __repr__(self):
+ # this is needed for snapshot testing, GenericRepr uses repr to built the snapshot
+ ref_target = '?'
+ if hasattr(self.x, 'descriptor'):
+ ref_target = self.x.descriptor()
+ else:
+ par = self.x.parent
+ if hasattr(self.x, 'name'):
+ par_d = ''
+ if hasattr(par, 'descriptor'):
+ par_d = par.descriptor() + '.'
+ elif hasattr(par, 'name'):
+ par_d = par.name + '.'
+ ref_target = f'{par_d}{self.x.name}'
+
+ return f'['
+
+
+@NodeDataclass
+class Node:
+ """
+ Base class for all AST nodes. Includes source location information, code comments and a parenting mechanism so that
+ clients can traverse all child and parent nodes.
+ """
+
+ id_location: str = field(init=False, repr=False, hash=False, compare=False, default=None)
+ "LineNumber:LinePosition, this is set dynamically in common.make"
+ start_location: SourceLocation = field(init=False, repr=False, hash=False, compare=False, default=None)
+ "Source start location of this node (column is inclusive)"
+ end_location: SourceLocation = field(init=False, repr=False, hash=False, compare=False, default=None)
+ "Source end location of this node (column is exclusive)"
+ start_buffer_index: int = field(init=False, repr=False, hash=False, compare=False, default=-1)
+ "Source start (0-based) position in the input text buffer(inclusive)"
+ end_buffer_index: int = field(init=False, repr=False, hash=False, compare=False, default=-1)
+ "Source end (0-based) position in the input text buffer(exclusive)"
+
+ parent: Optional['Node'] = field(init=False, repr=False, hash=False, compare=False, default=None)
+ comments: Optional[list[str]] = field(init=False, repr=False, hash=False, compare=False, default_factory=list)
+
+ def __post_init__(self):
+ self._set_child_parents()
+
+ def get_source_span(self):
+ return SourceLocationSpan(self.start_location, self.end_location)
+
+ def linenumber(self) -> int:
+ return int(self.location.split(":")[0])
+
+ def source_location(self):
+ if hasattr(self, 'scope') and self.scope:
+ from solidity_parser.ast.symtab import FileScope
+ file_scope = self.scope.find_first_ancestor_of(FileScope)
+ file_name = file_scope.source_unit_name
+ else:
+ file_name = ''
+ return f'{file_name} @{self.location}'
+
+ def offset(self) -> int:
+ return int(self.location.split(":")[1])
+
+ def get_children(self, predicate: Callable[['Node'], bool] = None) -> Generator['Node', None, None]:
+ if not predicate:
+ predicate = lambda _: True
+ # get the dataclass fields instead of vars() here: two benefits:
+ # we loop fewer times as there are less things
+ # we include only the explicit fields of each dataclass so won't pick up accidental recursions
+ for k, dfield in self.__dataclass_fields__.items():
+ if dfield.hash:
+ continue
+
+ val = getattr(self, k)
+ # Don't include parent or Refs
+ # or NodeLists (done implicitly by generator)
+ if val is self.parent:
+ continue
+
+ if isinstance(val, Node) and predicate(val):
+ yield val
+ elif isinstance(val, (list, tuple)):
+ yield from [v for v in val if isinstance(v, Node) and predicate(v)]
+
+ def get_all_children(self, predicate: Callable[['Node'], bool] = None) -> Generator['Node', None, None]:
+ for direct_child in self.get_children():
+ yield direct_child
+ yield from direct_child.get_all_children(predicate)
+
+ def _set_child_parents(self):
+ for child in self.get_children():
+ child.parent = self
+
+ def __deepcopy__(self, memodict):
+ new_fields = {}
+ for name, dfield in self.__dataclass_fields__.items():
+ if name == 'parent':
+ # don't climb up the tree/copy the parent
+ continue
+ # just confirm it needs to be passed to the constructor
+ if not dfield.init:
+ continue
+
+ current_value = getattr(self, name)
+ if isinstance(current_value, (Node, list, tuple)) and not isinstance(current_value, Ref):
+ new_fields[name] = deepcopy(current_value, memodict)
+ else:
+ # copy stuff like str, int
+ new_fields[name] = current_value
+ klass = self.__class__
+ # create the copy by instantiating it like a normal Node, i.e. the parent of the children are set here
+ new_obj = klass(**new_fields)
+ return new_obj
+
+ def code_str(self):
+ raise NotImplementedError()
+
diff --git a/src/solidity_parser/ast/parsers/common.py b/src/solidity_parser/ast/parsers/common.py
index ae068ba..b591702 100644
--- a/src/solidity_parser/ast/parsers/common.py
+++ b/src/solidity_parser/ast/parsers/common.py
@@ -1,8 +1,8 @@
import antlr4
-from antlr4.tree.Tree import TerminalNode
import inspect
-from solidity_parser.ast.solnodes import Node
-import solidity_parser.ast.solnodes as solnodes
+
+from solidity_parser.ast import nodebase, solnodes
+
class ParserBase:
def __init__(self, subparsers, token_stream):
@@ -16,7 +16,7 @@ def make(self, rule: antlr4.ParserRuleContext, default=None):
# this can happen with rule labels like in array slice if the
# optional subrule in the grammar doesn't match
- if isinstance(rule, antlr4.Token) or isinstance(rule, TerminalNode):
+ if isinstance(rule, antlr4.Token) or isinstance(rule, antlr4.tree.Tree.TerminalNode):
return None
# find the appropriate _ creation method based on
@@ -70,7 +70,7 @@ def copy_source_data(self, decorated_node, node_to_decorate):
return node_to_decorate
def wrap_node(self, rule, node, add_comments=False):
- if isinstance(node, Node):
+ if isinstance(node, nodebase.Node):
if hasattr(rule, 'symbol'):
rule = rule.symbol
# we add 1 to each column in each of these because we used 1 based columns, see solnodes.SourceLocation
@@ -78,9 +78,9 @@ def wrap_node(self, rule, node, add_comments=False):
# for terminal node symbols
node.location = f'{rule.line}:{rule.start}'
- node.start_location = solnodes.SourceLocation(rule.line, rule.column + 1)
+ node.start_location = nodebase.SourceLocation(rule.line, rule.column + 1)
token_len = rule.stop - rule.start + 1
- node.end_location = solnodes.SourceLocation(rule.line, rule.column + token_len + 1)
+ node.end_location = nodebase.SourceLocation(rule.line, rule.column + token_len + 1)
node.start_buffer_index = rule.start
node.end_buffer_index = rule.stop + 1
@@ -88,9 +88,9 @@ def wrap_node(self, rule, node, add_comments=False):
# this is the normal case
node.location = f'{rule.start.line}:{rule.start.start}'
- node.start_location = solnodes.SourceLocation(rule.start.line, rule.start.column + 1)
+ node.start_location = nodebase.SourceLocation(rule.start.line, rule.start.column + 1)
col_offset = rule.stop.stop - rule.stop.start + 1
- node.end_location = solnodes.SourceLocation(rule.stop.line, rule.stop.column + col_offset + 1)
+ node.end_location = nodebase.SourceLocation(rule.stop.line, rule.stop.column + col_offset + 1)
node.start_buffer_index = rule.start.start
node.end_buffer_index = rule.stop.stop + 1
diff --git a/src/solidity_parser/ast/parsers/parsers060.py b/src/solidity_parser/ast/parsers/parsers060.py
index 233b5be..146e372 100644
--- a/src/solidity_parser/ast/parsers/parsers060.py
+++ b/src/solidity_parser/ast/parsers/parsers060.py
@@ -1,7 +1,7 @@
import sys
from solidity_parser.ast.parsers.common import ParserBase, get_all_subparsers, map_helper
from solidity_parser.ast.parsers.errors import invalid_solidity
-from solidity_parser.ast import solnodes
+from solidity_parser.ast import solnodes, types as soltypes
from solidity_parser.grammar.v060.SolidityParser import SolidityParser
@@ -39,11 +39,13 @@ def custom_parsers():
'EventParameterListContext': ParserBase.make_all,
}
+
def _block(parser, block: SolidityParser.BlockContext):
return solnodes.Block(
parser.make_all(block)
)
+
def _if(parser, stmt: SolidityParser.IfStatementContext):
return solnodes.If(
parser.make(stmt.expression()),
@@ -140,7 +142,7 @@ def _var_decl_stmt(parser, stmt: SolidityParser.VariableDeclarationStatementCont
# e.g: var (, mantissa, exponent) = unpackPrice(price); which is deprecated in 0.4.20
# desugar it into multiple variables, TODO: figure out the types in a later type inference pass
names = parser.make(stmt.identifierList())
- variables = [solnodes.Var(solnodes.VarType(), name, None) for name in names]
+ variables = [solnodes.Var(soltypes.VarType(), name, None) for name in names]
is_tuple = True
elif stmt.variableDeclaration() is not None:
variables = [parser.make(stmt.variableDeclaration())]
@@ -243,12 +245,12 @@ def _unary_post_op(parser, expr: SolidityParser.UnaryPostOpContext):
def _type_name(parser, type_name: SolidityParser.TypeNameContext):
if type_name.typeName():
if type_name.expression():
- return solnodes.VariableLengthArrayType(
+ return soltypes.VariableLengthArrayType(
parser.make(type_name.typeName()),
parser.make(type_name.expression())
)
else:
- return solnodes.ArrayType(
+ return soltypes.ArrayType(
parser.make(type_name.typeName())
)
else:
@@ -256,17 +258,32 @@ def _type_name(parser, type_name: SolidityParser.TypeNameContext):
def _mapping_type(parser, mapping_type: SolidityParser.MappingContext):
- return solnodes.MappingType(
+ return soltypes.MappingType(
parser.make(mapping_type.mappingKey()),
parser.make(mapping_type.typeName())
)
+def params_to_types(params: solnodes.Parameter):
+ # TODO: add name + storage to FunctionType. Is it even necessary?
+ # old solnodes1.FunctionType had this but solnodes2.FunctionType didn't and now types.FunctionType doesn't either
+ # so this informtion isn't stored.
+ # Idea: create a new mixin that can be added to all the Type subclasses OR create a new NamedType that has the
+ # actual type as an attr and redirects Type calls to the attr. e.g.
+ # class NamedType(Type):
+ # name: Ident
+ # ttype: Type
+ # storage: ...
+ # def __getattr__(self, name):
+ # # checks...
+ # return getattr(self.ttype, name)
+ return [p.var_type for p in params]
+
def _function_type_name(parser, function_type: SolidityParser.FunctionTypeNameContext):
- return solnodes.FunctionType(
- parser.make(function_type.parameterList()),
- parser.make(function_type.modifierList()),
- parser.make(function_type.returnParameters())
+ return soltypes.FunctionType(
+ params_to_types(parser.make(function_type.parameterList(), default=[])),
+ params_to_types(parser.make(function_type.returnParameters(), default=[])),
+ parser.make(function_type.modifierList(), default=[])
)
@@ -313,15 +330,15 @@ def _primary(parser, expr: SolidityParser.PrimaryExpressionContext):
elif expr.typeNameExpression() is not None:
base_type = parser.make(expr.typeNameExpression())
if expr.arrayBrackets():
- return solnodes.ArrayType(base_type)
+ return soltypes.ArrayType(base_type)
else:
return base_type
elif expr.identifier() is not None:
# In the 080 grammar primary expressions hit 'identifier' first. To match this, if this isn't
# an array type, return as an ident
if expr.arrayBrackets():
- base_type = solnodes.UserType(parser.make(expr.identifier()))
- return solnodes.ArrayType(base_type)
+ base_type = soltypes.UserType(parser.make(expr.identifier()))
+ return soltypes.ArrayType(base_type)
else:
return parser.make(expr.identifier())
else:
@@ -401,37 +418,37 @@ def _catch_clause(parser, clause: SolidityParser.CatchClauseContext):
def _elementary_type_name(parser, name: SolidityParser.ElementaryTypeNameContext):
if name.addressType():
payable = name.addressType().PayableKeyword() is not None
- return solnodes.AddressType(payable)
+ return soltypes.AddressType(payable)
elif name.BoolType():
- return solnodes.BoolType()
+ return soltypes.BoolType()
elif name.StringType():
- return solnodes.StringType()
+ return soltypes.StringType()
elif name.VarType():
- return solnodes.VarType()
+ return soltypes.VarType()
elif name.Int():
size_str = name.Int().getText()[3:]
size = int(size_str) if size_str else 256
- return solnodes.IntType(True, size)
+ return soltypes.IntType(True, size)
elif name.Uint():
size_str = name.Uint().getText()[4:]
size = int(size_str) if size_str else 256
- return solnodes.IntType(False, size)
+ return soltypes.IntType(False, size)
elif name.AByte():
# 'byte' is a type alias for 'bytes1' (according to docs)
- return solnodes.FixedLengthArrayType(solnodes.ByteType(), 1)
+ return soltypes.FixedLengthArrayType(soltypes.ByteType(), 1)
elif name.Byte():
if name.Byte().getText() == 'bytes':
- return solnodes.BytesType()
+ return soltypes.BytesType()
else:
size_str = name.Byte().getText()[5:]
size = int(size_str)
- return solnodes.FixedLengthArrayType(solnodes.ByteType(), size)
+ return soltypes.FixedLengthArrayType(soltypes.ByteType(), size)
else:
raise NotImplementedError('fixed/ufixed')
def _user_defined_type(parser, name: SolidityParser.UserDefinedTypeNameContext):
- return solnodes.UserType(solnodes.Ident(name.getText()))
+ return soltypes.UserType(solnodes.Ident(name.getText()))
def _modifier_invocation(parser, modifier: SolidityParser.ModifierInvocationContext):
@@ -621,7 +638,7 @@ def _using_for_declaration(parser, using_for_declaration: SolidityParser.UsingFo
if using_for_declaration.typeName():
override_type = parser.make(using_for_declaration.typeName())
else:
- override_type = solnodes.AnyType()
+ override_type = soltypes.AnyType()
return solnodes.UsingDirective(
parser.make(using_for_declaration.identifier()),
diff --git a/src/solidity_parser/ast/parsers/parsers080.py b/src/solidity_parser/ast/parsers/parsers080.py
index b0c852e..19c05f3 100644
--- a/src/solidity_parser/ast/parsers/parsers080.py
+++ b/src/solidity_parser/ast/parsers/parsers080.py
@@ -3,7 +3,7 @@
from solidity_parser.ast.parsers.errors import assert_invalid_path, unsupported_feature
import solidity_parser.ast.parsers.parsers060 as parsers060
from solidity_parser.grammar.v080.SolidityParser import SolidityParser
-from solidity_parser.ast import solnodes
+from solidity_parser.ast import solnodes, types as soltypes
class Parser080(ParserBase):
@@ -140,7 +140,7 @@ def _library_definition(parser, library_definition: SolidityParser.LibraryDefini
def _inheritance_specifier(parser, inheritance_specifier: SolidityParser.InheritanceSpecifierContext):
type_name = parser.make(inheritance_specifier.identifierPath())
return solnodes.InheritSpecifier(
- parser.wrap_node(inheritance_specifier.identifierPath(), solnodes.UserType(type_name)),
+ parser.wrap_node(inheritance_specifier.identifierPath(), soltypes.UserType(type_name)),
parser.make(inheritance_specifier.callArgumentList(), default=[])
)
@@ -342,7 +342,7 @@ def _error_parameter(parser, error_parameter: SolidityParser.ErrorParameterConte
def _using_directive(parser, using_directive: SolidityParser.UsingDirectiveContext):
if using_directive.Mul():
- override_type = solnodes.AnyType()
+ override_type = soltypes.AnyType()
else:
override_type = parser.make(using_directive.typeName())
@@ -356,7 +356,7 @@ def _override_specifier(parser, override_specific: SolidityParser.OverrideSpecif
overrides = parser.make_all_rules(override_specific.identifierPath())
return solnodes.OverrideSpecifier(
- map_helper(lambda override: parser.copy_source_data(override, solnodes.UserType(override)), overrides)
+ map_helper(lambda override: parser.copy_source_data(override, soltypes.UserType(override)), overrides)
)
@@ -459,15 +459,6 @@ def _expr_stmt(parser, stmt: SolidityParser.ExpressionStatementContext):
)
-def _try(parser, stmt: SolidityParser.TryStatementContext):
- return solnodes.Try(
- parser.make(stmt.expression()),
- parser.make(stmt.parameterList(), default=[]),
- parser.make(stmt.block()),
- parser.make_all_rules(stmt.catchClause())
- )
-
-
def _catch_clause(parser, catch_clause: SolidityParser.CatchClauseContext):
return solnodes.Catch(
parser.make(catch_clause.identifier()),
@@ -545,25 +536,25 @@ def _meta_type(parser, meta_type: SolidityParser.MetaTypeContext):
def _type_name(parser, type_name: SolidityParser.TypeNameContext):
if type_name.typeName():
if type_name.expression():
- return solnodes.VariableLengthArrayType(
+ return soltypes.VariableLengthArrayType(
parser.make(type_name.typeName()),
parser.make(type_name.expression())
)
else:
- return solnodes.ArrayType(
+ return soltypes.ArrayType(
parser.make(type_name.typeName())
)
elif type_name.identifierPath():
- return solnodes.UserType(parser.make_first(type_name))
+ return soltypes.UserType(parser.make_first(type_name))
else:
return parser.make_first(type_name)
def _function_type_name(parser, function_type: SolidityParser.FunctionTypeNameContext):
- return solnodes.FunctionType(
- parser.make(function_type.arguments),
- parser.make_all_rules(function_type.visibility()) + parser.make_all_rules(function_type.stateMutability()),
- parser.make(function_type.returnParameters)
+ return soltypes.FunctionType(
+ parsers060.params_to_types(parser.make(function_type.arguments, default=[])),
+ parsers060.params_to_types(parser.make(function_type.returnParameters, default=[])),
+ parser.make_all_rules(function_type.visibility()) + parser.make_all_rules(function_type.stateMutability())
)
@@ -571,8 +562,8 @@ def _mapping_type(parser, mapping: SolidityParser.MappingTypeContext):
key = parser.make(mapping.key)
# Previous grammars had the key as a type, 0.8 grammar defined is as a raw ident path, so wrap it here
if isinstance(key, solnodes.Ident):
- key = parser.wrap_node(mapping.key, solnodes.UserType(key))
- return solnodes.MappingType(
+ key = parser.wrap_node(mapping.key, soltypes.UserType(key))
+ return soltypes.MappingType(
key,
parser.make(mapping.value)
)
@@ -693,25 +684,25 @@ def _unicode_string_literal(parser, literal: SolidityParser.UnicodeStringLiteral
def _elementary_type_name(parser, name: SolidityParser.ElementaryTypeNameContext):
if name.Address():
payable = name.Payable() is not None
- return solnodes.AddressType(payable)
+ return soltypes.AddressType(payable)
elif name.Bool():
- return solnodes.BoolType()
+ return soltypes.BoolType()
elif name.String():
- return solnodes.StringType()
+ return soltypes.StringType()
elif name.Bytes():
- return solnodes.BytesType()
+ return soltypes.BytesType()
elif name.SignedIntegerType():
size_str = name.SignedIntegerType().getText()[3:]
size = int(size_str) if size_str else 256
- return solnodes.IntType(True, size)
+ return soltypes.IntType(True, size)
elif name.UnsignedIntegerType():
size_str = name.UnsignedIntegerType().getText()[4:]
size = int(size_str) if size_str else 256
- return solnodes.IntType(False, size)
+ return soltypes.IntType(False, size)
elif name.FixedBytes():
size_str = name.FixedBytes().getText()[5:]
size = int(size_str)
- return solnodes.FixedLengthArrayType(solnodes.ByteType(), size)
+ return soltypes.FixedLengthArrayType(soltypes.ByteType(), size)
elif name.Fixed() or name.Ufixed():
return unsupported_feature('fixed/unfixed type')
else:
diff --git a/src/solidity_parser/ast/parsers/parsers08_22.py b/src/solidity_parser/ast/parsers/parsers08_22.py
index f985f98..a35e507 100644
--- a/src/solidity_parser/ast/parsers/parsers08_22.py
+++ b/src/solidity_parser/ast/parsers/parsers08_22.py
@@ -1,5 +1,5 @@
import sys
-from solidity_parser.ast import solnodes
+from solidity_parser.ast import solnodes, types as soltypes
from solidity_parser.ast.parsers import parsers080
from solidity_parser.ast.parsers import parsers088
from solidity_parser.ast.parsers.parsers080 import custom_parsers as custom_parsers080
@@ -48,7 +48,7 @@ def _using_directive_alias(parser, rule: SolidityParser.UsingDirectiveAliasConte
def _using_directive(parser, rule: SolidityParser.UsingDirectiveContext):
### overrides the base UsingDirectiveContext rule ###
if rule.Mul():
- override_type = solnodes.AnyType()
+ override_type = soltypes.AnyType()
else:
override_type = parser.make(rule.typeName())
@@ -88,10 +88,10 @@ def _mapping_type(parser, rule: SolidityParser.MappingTypeContext):
### overrides the base MappingTypeContext rule ###
key = parser.make(rule.key)
if isinstance(key, solnodes.Ident):
- key = solnodes.UserType(key)
+ key = soltypes.UserType(key)
value = parser.make(rule.value)
key_name = parser.make(rule.name1)
value_name = parser.make(rule.name2)
- return solnodes.MappingType(key, value, key_name, value_name)
+ return soltypes.MappingType(key, value, key_name, value_name)
diff --git a/src/solidity_parser/ast/solnodes.py b/src/solidity_parser/ast/solnodes.py
index 103adc8..81e994d 100644
--- a/src/solidity_parser/ast/solnodes.py
+++ b/src/solidity_parser/ast/solnodes.py
@@ -1,113 +1,22 @@
+import typing
from dataclasses import dataclass, field
from enum import Enum
-from typing import List, Any, Union, Optional, NamedTuple
-from abc import ABC, abstractmethod
-from collections import namedtuple
-
-
-class SourceLocation(NamedTuple):
- line: int
- "Line number, beginning at 1"
- column: int
- "Column number, beginning at 1. E.g. the first character on the line is at column 1."
-
-
-class SourceLocationSpan(NamedTuple):
- start: SourceLocation
- end: SourceLocation
-
- def does_contain(self, loc: SourceLocation):
- """
- Checks whether the given 'loc' location is contained within this span.
- E.g. if this span represents ((5,1), (10, 1)), i.e lines 5 to 10 and loc is (6, 1), the location is contained
- :param loc:
- :return:
- """
-
- if loc.line < self.start.line or loc.line > self.end.line:
- # outside the line range
- return False
-
- # below: the location is in the line range
-
- before_start, after_end = loc.column < self.start.column, loc.column > self.end.column
- on_start_line, on_end_line = loc.line == self.start.line, loc.line == self.end.line
-
- if on_start_line and on_end_line:
- # i.e. start and end line are the same, check within column range
- return not (before_start or after_end)
- elif on_start_line:
- # on the start line (not on the end line, end line != start line), check after the start col
- return not before_start
- elif on_end_line:
- # above but for end line
- return not after_end
- else:
- # start and end lines are not the same and the loc is somewhere between, but not on the start or end lines
- return True
-
-
-class Node:
- # TODO: want to get rid of this
- location: str
- "LineNumber:LinePosition, this is set dynamically in common.make"
- comments: List[str]
-
- start_location: SourceLocation
- "Source start location of this node (column is inclusive)"
- end_location: SourceLocation
- "Source end location of this node (column is exclusive)"
-
- start_buffer_index: int
- "Source start (0-based) position in the input text buffer(inclusive)"
- end_buffer_index: int
- "Source end (0-based) position in the input text buffer(exclusive)"
-
- def get_source_span(self):
- return SourceLocationSpan(self.start_location, self.end_location)
-
- def __post_init__(self):
- for child in self.get_children():
- child.parent = self
-
- def get_children(self):
- parent = self.parent if hasattr(self, 'parent') else None
-
- for val in vars(self).values():
- if parent and val is parent:
- continue
-
- if isinstance(val, Node):
- yield val
- elif isinstance(val, (list, tuple)):
- yield from [v for v in val if isinstance(v, Node)]
-
- def get_all_children(self):
- for direct_child in self.get_children():
- yield direct_child
- yield from direct_child.get_all_children()
-
- def linenumber(self) -> int:
- return int(self.location.split(":")[0])
-
- def source_location(self):
- if hasattr(self, 'scope') and self.scope:
- from solidity_parser.ast.symtab import FileScope
- file_scope = self.scope.find_first_ancestor_of(FileScope)
- file_name = file_scope.source_unit_name
- else:
- file_name = ''
- return f'{file_name} @{self.location}'
+from typing import Any, Optional
+from solidity_parser.ast import nodebase, types as soltypes
+
- def offset(self) -> int:
- return int(self.location.split(":")[1])
+@nodebase.NodeDataclass
+class AST1Node(nodebase.Node):
+ # scope doesn't get included in get_children or hash as long as it's not a subclass of nodebase.Node
+ scope: 'Scope' = field(default=None, init=False, repr=False, compare=False, hash=False)
+ ast2_node: 'AST2Node' = field(default=None, init=False, repr=False, compare=False, hash=False)
-class Stmt(Node):
+class Stmt(AST1Node):
pass
-class Expr(Node):
+class Expr(AST1Node):
pass
@@ -119,164 +28,6 @@ class Ident(Expr):
def __str__(self): return self.text
-class Type(Node, ABC):
- """ Base class for all Solidity types """
-
- @abstractmethod
- def __str__(self):
- pass
-
- def is_array(self) -> bool:
- return False
-
- def is_string(self) -> bool:
- return False
-
- def is_function(self) -> bool:
- return False
-
- def is_int(self) -> bool:
- return False
-
- def is_mapping(self) -> bool:
- return False
-
- def is_address(self) -> bool:
- return False
-
- def type_key(self):
- return str(self)
-
-
-@dataclass
-class ArrayType(Type):
- """ Single dimension array type with no size attributes """
- base_type: Type
-
- def __str__(self): return f"{self.base_type}[]"
-
- def is_array(self) -> bool:
- return True
-
-
-@dataclass
-class FixedLengthArrayType(ArrayType):
- """ Array type with a known length that is determined at compile time """
- size: int
-
- def __str__(self): return f"{self.base_type}[{self.size}]"
-
-
-@dataclass
-class VariableLengthArrayType(ArrayType):
- """ Array type with a length that is determined at runtime"""
- size: Expr
-
- def __str__(self): return f"{self.base_type}[{self.size}]"
-
-
-@dataclass
-class AddressType(Type):
- """ Solidity address/address payable type """
- is_payable: bool
-
- def __str__(self): return f"address{' payable' if self.is_payable else ''}"
-
- def is_address(self) -> bool:
- return True
-
-
-@dataclass
-class ByteType(Type):
- """ Single 8bit byte type """
-
- def __str__(self): return "byte"
-
-
-@dataclass
-class BytesType(ArrayType):
- base_type: Type = field(default_factory=ByteType, init=False)
-
- def __str__(self): return 'bytes'
-
-
-@dataclass
-class IntType(Type):
- """ Solidity native integer type of various bit length and signedness"""
-
- is_signed: bool
- """ Whether the type is a signed int or unsigned int """
- size: int
- """ Size of the type in bits """
-
- def __str__(self): return f"{'int' if self.is_signed else 'uint'}{self.size}"
-
- def is_int(self) -> bool:
- return True
-
-
-class BoolType(Type):
- """ Solidity native boolean type"""
-
- def __str__(self): return "bool"
-
-
-class StringType(Type):
- """ Solidity native string type"""
-
- def __str__(self): return "string"
-
- def is_array(self) -> bool:
- return True
-
- def is_string(self) -> bool:
- return True
-
-
-class VarType(Type):
- """ Type that wasn't explicitly identified in the code
-
- This type should not be used without running a subsequent type inference pass.
-
- An example variable declaration that would use this type symbol: 'var (, mantissa, exponent) = ... '
- """
-
- # I've only seen this once in ~10000 contracts where a contract used the 'var' keyword
-
- def __str__(self): return "var"
-
-
-class AnyType(Type):
- """ Type that is used only in 'using' declarations to specify that the declaration is overriding all possible types
-
- For example in the declaration 'using SomeLibrary for *', the overriden type here is AnyType(every type
- that is imported from SomeLibrary)
- """
-
- def __str__(self): return "*"
-
-
-@dataclass
-class MappingType(Type):
- """ Type that represents a function mapping definition
-
- For example in the mapping '(uint x => Campaign c)', src would be 'unit' and the dst would be 'Campaign',
- src_key would be 'x' and dst_key would be 'c'
- """
- src: Type
- dst: Type
- src_name: Ident = None
- dst_name: Ident = None
-
- def __str__(self):
- def _name(ident):
- return (' ' + str(ident)) if ident else ''
- return f"({self.src}{_name(self.src_name)} => {self.dst}{_name(self.dst_name)})"
-
- def is_mapping(self) -> bool:
- return True
-
-
class Location(Enum):
""" Solidity reference type storage locations
@@ -298,19 +49,6 @@ class Location(Enum):
def __str__(self): return self.value
-@dataclass
-class UserType(Type):
- """ Type invoked using a valid Solidity reference, e.g. a class, contract, library, enum, etc name"""
- name: Ident
-
- def __str__(self): return str(self.name)
-
-
-class NoType(Type):
- def __str__(self):
- return ''
-
-
@dataclass
class NamedArg(Expr):
""" A name-value pair used for calling functions with options """
@@ -362,6 +100,13 @@ class Literal(Expr):
value: Any
unit: Unit = None
+ def code_str(self):
+ # shim for symtab to get type_key for ArrayType sizes, this should match the solnodes2.Literal code_str
+ if isinstance(self.value, str):
+ return f'"{self.value}"'
+ else:
+ return str(self.value)
+
class UnaryOpCode(Enum):
""" Single operand operation types"""
@@ -448,7 +193,7 @@ class New(Expr):
This expression must then be used as the base object in a constructor call to instantiate it.
"""
- type_name: Type
+ type_name: soltypes.Type
@dataclass
@@ -458,7 +203,7 @@ class NewInlineArray(Expr):
An inline array is one where the elements are explicitly stated in the definition, for example:
'int[5] foo2 = [1, 0, 0, 0, 0];'
"""
- elements: List[Expr]
+ elements: list[Expr]
@dataclass
@@ -467,7 +212,7 @@ class PayableConversion(Expr):
For example: 'payable(address(myAddressHex))'
"""
- args: List[Expr]
+ args: list[Expr]
@dataclass
@@ -497,26 +242,26 @@ class CallFunction(Expr):
""" Invokes a function """
callee: Expr
""" This callee is most likely a GetMember expression but can be any callable """
- modifiers: List
- args: List[Expr]
+ modifiers: list
+ args: list[Expr]
@dataclass
-class Var(Node):
- var_type: Type
+class Var(AST1Node):
+ var_type: soltypes.Type
var_name: Ident
var_loc: Optional[Location] = None
@dataclass
class VarDecl(Stmt):
- variables: List[Var]
+ variables: list[Var]
value: Expr
is_lhs_tuple: bool = False
@dataclass
-class Parameter(Node):
+class Parameter(AST1Node):
var_type: Ident
var_loc: Location
var_name: Ident
@@ -532,7 +277,7 @@ class ExprStmt(Stmt):
@dataclass
class Block(Stmt):
- stmts: List[Stmt]
+ stmts: list[Stmt]
is_unchecked: bool = False
@@ -546,16 +291,16 @@ class If(Stmt):
@dataclass
class Catch(Stmt):
ident: Ident
- parameters: List[Parameter]
+ parameters: list[Parameter]
body: Block
@dataclass
class Try(Stmt):
expr: Expr
- return_parameters: List[Parameter]
+ return_parameters: list[Parameter]
body: Block
- catch_clauses: List[Catch]
+ catch_clauses: list[Catch]
@dataclass
@@ -613,7 +358,7 @@ class Throw(Stmt):
@dataclass
-class Modifier(Node):
+class Modifier(AST1Node):
pass
@@ -646,22 +391,22 @@ class MutabilityModifier2(Modifier):
@dataclass
class InvocationModifier(Modifier):
name: Ident
- arguments: List[Expr]
+ arguments: list[Expr]
@dataclass
class OverrideSpecifier(Modifier):
- arguments: List[UserType]
+ arguments: list[soltypes.UserType]
-class SourceUnit(Node):
+class SourceUnit(AST1Node):
pass
@dataclass
class PragmaDirective(SourceUnit):
name: Ident
- value: Union[str, Expr]
+ value: str | Expr
@dataclass
@@ -680,18 +425,18 @@ class UnitImportDirective(ImportDirective):
@dataclass
-class SymbolAlias(Node):
+class SymbolAlias(AST1Node):
symbol: Ident
alias: Ident
@dataclass
class SymbolImportDirective(ImportDirective):
- aliases: List[SymbolAlias]
+ aliases: list[SymbolAlias]
@dataclass
-class ContractPart(Node):
+class ContractPart(AST1Node):
pass
@@ -706,63 +451,64 @@ def __str__(self):
@dataclass
class FunctionDefinition(SourceUnit, ContractPart):
- name: Union[Ident, SpecialFunctionKind]
- parameters: List[Parameter]
- modifiers: List[Modifier]
- returns: List[Parameter]
+ name: Ident | SpecialFunctionKind
+ parameters: list[Parameter]
+ modifiers: list[Modifier]
+ returns: list[Parameter]
code: Block
@dataclass
class ModifierDefinition(ContractPart):
name: Ident
- parameters: List[Parameter]
- modifiers: List[Modifier]
+ parameters: list[Parameter]
+ modifiers: list[Modifier]
code: Block
@dataclass
-class StructMember(Node):
- member_type: Type
+class StructMember(AST1Node):
+ member_type: soltypes.Type
name: Ident
@dataclass
class StructDefinition(SourceUnit, ContractPart):
name: Ident
- members: List[StructMember]
+ members: list[StructMember]
@dataclass
class EnumDefinition(SourceUnit, ContractPart):
name: Ident
- values: List[Ident]
+ values: list[Ident]
@dataclass
class StateVariableDeclaration(ContractPart):
- var_type: Type
- modifiers: List[Modifier]
+ var_type: soltypes.Type
+ modifiers: list[Modifier]
name: Ident
initial_value: Expr
@dataclass
class ConstantVariableDeclaration(SourceUnit):
- var_type: Type
+ var_type: soltypes.Type
name: Ident
initial_value: Expr
+# TODO: rename with -Definition suffix
@dataclass
class UserValueType(SourceUnit, ContractPart):
name: Ident
- value: Type
+ value: soltypes.Type
@dataclass
-class EventParameter(Node):
- var_type: Type
+class EventParameter(AST1Node):
+ var_type: soltypes.Type
name: Ident
is_indexed: bool
@@ -771,97 +517,87 @@ class EventParameter(Node):
class EventDefinition(ContractPart):
name: Ident
is_anonymous: bool
- parameters: List[EventParameter]
+ parameters: list[EventParameter]
@dataclass
-class ErrorParameter(Node):
- var_type: Type
+class ErrorParameter(AST1Node):
+ var_type: soltypes.Type
name: Ident
@dataclass
class ErrorDefinition(SourceUnit, ContractPart):
name: Ident
- parameters: List[ErrorParameter]
+ parameters: list[ErrorParameter]
@dataclass
-class UsingAttachment(Node):
+class UsingAttachment(AST1Node):
member_name: Ident
@dataclass
-class UsingOperatorBinding(Node):
+class UsingOperatorBinding(AST1Node):
member_name: Ident
- operator: Union[UnaryOpCode, BinaryOpCode]
+ operator: UnaryOpCode | BinaryOpCode
@dataclass
class UsingDirective(ContractPart):
library_name: Ident
# either override_type or bindings is allowed but not both at the same time
- override_type: Type
- attachments_or_bindings: List[Union[UsingAttachment, UsingOperatorBinding]] = field(default_factory=list)
+ override_type: soltypes.Type
+ attachments_or_bindings: list[UsingAttachment | UsingOperatorBinding] = field(default_factory=list)
is_global: bool = field(default=False)
@dataclass
-class InheritSpecifier(Node):
- name: UserType
- args: List[Expr]
+class InheritSpecifier(AST1Node):
+ name: soltypes.UserType
+ args: list[Expr]
@dataclass
class ContractDefinition(SourceUnit):
name: Ident
is_abstract: bool
- inherits: List[InheritSpecifier]
- parts: List[ContractPart]
+ inherits: list[InheritSpecifier]
+ parts: list[ContractPart]
@dataclass
class InterfaceDefinition(SourceUnit):
name: Ident
- inherits: List[InheritSpecifier]
- parts: List[ContractPart]
+ inherits: list[InheritSpecifier]
+ parts: list[ContractPart]
@dataclass
class LibraryDefinition(SourceUnit):
name: Ident
- parts: List[ContractPart]
+ parts: list[ContractPart]
@dataclass
class CreateMetaType(Expr):
- base_type: Type
+ base_type: soltypes.Type
-@dataclass
-class FunctionType(Type):
- parameters: List[Parameter]
- modifiers: List[Modifier]
- return_parameters: List[Parameter]
-
- def __str__(self):
- # TODO
- return f'FT'
-
- def type_key(self):
- # doesn't include modifiers for now
- input_params = ', '.join([p.var_type.type_key() for p in self.parameters])
- output_params = ', '.join([p.var_type.type_key() for p in self.return_parameters])
- return f'function ({input_params}) returns ({output_params})'
-
- def is_function(self) -> bool:
- return True
-
-
-def has_modifier_kind(node, *kinds: Union[VisibilityModifierKind, MutabilityModifierKind]):
+def has_modifier_kind(node, *kinds: VisibilityModifierKind | MutabilityModifierKind):
if hasattr(node, 'modifiers'):
own_kinds = [m.kind for m in node.modifiers if hasattr(m, 'kind')]
for k in kinds:
if k in own_kinds:
return True
return False
+
+
+ModFunErrEvt: typing.TypeAlias = ModifierDefinition | FunctionDefinition | ErrorDefinition | EventDefinition
+
+
+Types: typing.TypeAlias = (soltypes.VariableLengthArrayType | soltypes.VoidType | soltypes.IntType
+ | soltypes.FunctionType | soltypes.ArrayType | soltypes.BytesType | soltypes.BoolType
+ | soltypes.AnyType | soltypes.MappingType | soltypes.UserType | soltypes.StringType
+ | soltypes.FixedLengthArrayType | soltypes.AddressType | soltypes.ByteType)
+
diff --git a/src/solidity_parser/ast/solnodes2.py b/src/solidity_parser/ast/solnodes2.py
index 15516c6..a19d5c4 100644
--- a/src/solidity_parser/ast/solnodes2.py
+++ b/src/solidity_parser/ast/solnodes2.py
@@ -1,16 +1,13 @@
from abc import ABC
-from dataclasses import dataclass, field
+from dataclasses import field
from enum import Enum
-from typing import List, Any, Union, TypeVar, Generic, Optional
-from copy import deepcopy
+from typing import Any, TypeVar, Union as U, TypeAlias
from collections import deque
-from solidity_parser.ast import solnodes as solnodes1
-
+from solidity_parser.ast import solnodes as solnodes1, types as soltypes, nodebase
from solidity_parser.ast.mro_helper import c3_linearise
from textwrap import indent
-import inspect
T = TypeVar('T')
@@ -29,214 +26,7 @@ def param_out(p):
return '(' + ', '.join([param_out(p) for p in ps]) + ')'
-def UIntType(size=256):
- return IntType(False, size)
-
-
-def Bytes(size=None):
- if size is not None:
- if isinstance(size, int):
- return FixedLengthArrayType(ByteType(), size)
- elif isinstance(size, Expr):
- return VariableLengthArrayType(ByteType(), size)
- else:
- raise NotImplementedError(f'{type(size)}')
- else:
- return BytesType()
-
-
-def is_byte_array(ttype: 'Type') -> bool:
- return (isinstance(ttype, ArrayType) and isinstance(ttype.base_type, ByteType)) or isinstance(ttype, BytesType)
-
-
-__REASON_CHILD__ = '__child__'
-__FIELD_PARENT__ = 'parent'
-__REASON_INIT__ = '__init__'
-
-
-def NodeDataclass(cls, *args, **kwargs):
- # Add a hash based on the elements that make up this node. This is required because dataclass doesn't generate a
- # hash for us unless we pass in unsafe_hash=True on the decorator for every node subclass and even if we do that
- # it can't hash lists. Since get_all_children returns a generator of nodes (i.e. no lists), we can hash it as a
- # tuple, i.e. a "snapshot hash"
- def compute_node_hash(self):
- return hash(tuple(self.get_all_children()))
-
- def __hash__(self):
- if not self._cached_hash:
- # this hash can be computed many times if the dataclass field that made this instance dirty is not a real
- # child, i.e. doesn't get returned in get_children() because its not a Node(e.g. the field is a List[str])
- # For now just allow this because we'd have to recurse on the object to see if it really makes a difference
- # to the hash, and it's not worth it
- self._cached_hash = self.compute_node_hash()
- return self._cached_hash
-
- actual_dataclass = dataclass(*[cls, *args], **kwargs)
-
- actual_init = actual_dataclass.__init__
- actual_setattr = actual_dataclass.__setattr__
-
- def __setattr__(self, name, value):
- # wrap lists as they are mutable in our own list type that can notify when elements are changed
- # since NodeList is also a list, this will take the existing nodelist and wrap it
- if isinstance(value, list):
- value = NodeList(self, value)
-
- actual_setattr(self, name, value)
- # if this attribute was declared as a dataclass field, the state of this node is dirty as the
- # contents changed
- if name in actual_dataclass.__dataclass_fields__:
- self._set_dirty(name, value)
-
- def _set_dirty(self, name, value):
- # in the case of lists, name can be an int or slice
-
- # a node is considered hash dirty if its direct children or grandchildren attributes are changed
- # - if the parent of a node is changed, the node does not become hash dirty
- # __FIELD_PARENT__ is triggered when the parent is changed
- # __REASON_CHILD__ is not a real attribute, it's triggered to alert the parent of this node that the child was
- # made hash dirty(e.g. because of a grandchild becoming hash dirty)
- # final case is for real attributes in this node that were just changed
- if name != __FIELD_PARENT__ or name == __REASON_CHILD__:
- # print("HashDirty: " + str(id(self))[9:] +" because of " + str(name))
- self._cached_hash = None
- if self.parent:
- # parent is recursively dirty
- self.parent._set_dirty(__REASON_CHILD__, self)
-
- def __init__(self, *args, **kwargs):
- actual_init(self, *args, **kwargs)
- self._cached_hash = None
-
- actual_dataclass.__hash__ = __hash__
- actual_dataclass.compute_node_hash = compute_node_hash
- actual_dataclass.__setattr__ = __setattr__
- actual_dataclass.__init__ = __init__
- actual_dataclass._set_dirty = _set_dirty
-
- return actual_dataclass
-
-
-@NodeDataclass
-class NodeList(list):
- def __init__(self, parent: 'Node', seq=()):
- super().__init__(seq)
- self.parent = parent
-
- def __str__(self):
- return list.__str__(self)
-
- def __repr__(self):
- return list.__repr__(self)
-
- def __setitem__(self, key, value):
- # seems to get called with slices too, that's why __setslice__ is stubbed with TODO
- super().__setitem__(key, value)
- self._set_dirty(key, value)
-
- def __delitem__(self, key):
- super().__delitem__(key)
- self._set_dirty(key, None)
-
- def __setslice__(self, i, j, sequence):
- raise NotImplemented
-
- def __eq__(self, other):
- if isinstance(other, list):
- return super().__eq__(other)
- raise NotImplemented
-
- def append(self, __object):
- ret = super().append(__object)
- self._set_dirty('__append__', __object)
- return ret
-
- def clear(self):
- ret = super().clear()
- self._set_dirty('__clear__', None)
- return ret
-
- def extend(self, __iterable):
- ret = super().extend(__iterable)
- self._set_dirty('__extend__', None)
- return ret
-
- def insert(self, __index, __object):
- ret = super().insert(__index, __object)
- self._set_dirty('__insert__', __object)
- return ret
-
- def pop(self, __index):
- ret = super().pop(__index)
- self._set_dirty('__pop__', None)
- return ret
-
- def remove(self, __value):
- ret = super().remove(__value)
- self._set_dirty('__remove__', None)
- return ret
-
- def reverse(self):
- ret = super().reverse()
- self._set_dirty('__reverse__', None)
- return ret
-
- def sort(self, *args, **kwargs):
- ret = super().sort(*args, **kwargs)
- self._set_dirty('__sort__', None)
- return ret
-
-
-@dataclass
-class Ref(Generic[T]):
- x: T
-
- def __repr__(self):
- # this is needed for snapshot testing, GenericRepr uses repr to built the snapshot
- ref_target = '?'
- if hasattr(self.x, 'descriptor'):
- ref_target = self.x.descriptor()
- else:
- par = self.x.parent
- if hasattr(self.x, 'name'):
- par_d = ''
- if hasattr(par, 'descriptor'):
- par_d = par.descriptor() + '.'
- elif hasattr(par, 'name'):
- par_d = par.name + '.'
- ref_target = f'{par_d}{self.x.name}'
-
- return f']['
-
-
-@NodeDataclass
-class Node:
- parent: Optional['Node'] = field(init=False, repr=False, hash=False, compare=False, default=None)
- comments: Optional[List[str]] = field(init=False, repr=False, hash=False, compare=False, default_factory=list)
-
- def get_children(self, predicate=None):
- if not predicate:
- predicate = lambda _: True
- # get the dataclass fields instead of vars() here: two benefits:
- # we loop fewer times as there are less things
- # we include only the explicit fields of each dataclass so won't pick up accidental recursions
- for k in self.__dataclass_fields__.keys():
- val = getattr(self, k)
- # Don't include parent or Refs
- # or NodeLists (done implicitly by generator)
- if val is self.parent:
- continue
-
- if isinstance(val, Node) and predicate(val):
- yield val
- elif isinstance(val, (list, tuple)):
- yield from [v for v in val if isinstance(v, Node) and predicate(v)]
-
- def get_all_children(self, predicate=None):
- for direct_child in self.get_children():
- yield direct_child
- yield from direct_child.get_all_children(predicate)
-
+class AST2Node(nodebase.Node):
def get_top_level_unit(self) -> 'TopLevelUnit':
parent = self
while parent:
@@ -245,132 +35,76 @@ def get_top_level_unit(self) -> 'TopLevelUnit':
parent = parent.parent
raise ValueError('Node has no top level unit')
- def __post_init__(self):
- self._set_child_parents()
- # self.created_in = inspect.stack()
-
- def _set_child_parents(self):
- for child in self.get_children():
- child.parent = self
-
- def __deepcopy__(self, memodict):
- new_fields = {}
- for name, dfield in self.__dataclass_fields__.items():
- if name == 'parent':
- # don't climb up the tree/copy the parent
- continue
- # just confirm it needs to be passed to the constructor
- if not dfield.init:
- continue
-
- current_value = getattr(self, name)
- if isinstance(current_value, (Node, list, tuple)) and not isinstance(current_value, Ref):
- new_fields[name] = deepcopy(current_value, memodict)
- else:
- # copy stuff like str, int
- new_fields[name] = current_value
- klass = self.__class__
- # create the copy by instantiating it like a normal Node, i.e. the parent of the children are set here
- new_obj = klass(**new_fields)
- return new_obj
- def code_str(self):
- raise NotImplementedError()
-
-
-@NodeDataclass
-class Type(Node, ABC):
- @staticmethod
- def are_matching_types(target_param_types, actual_param_types):
- if not len(target_param_types) == len(actual_param_types):
- return False
+class Stmt(AST2Node, ABC):
+ pass
- # check if the actual args types are passable to the target types
- return all([a.can_implicitly_cast_from(b) for a,b in zip(target_param_types, actual_param_types)])
- def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
- # Check whether actual_type can be converted to this type implicitly
- # Default case is if the types are equal
- return self == actual_type
+class Expr(AST2Node, ABC):
+ def type_of(self) -> soltypes.Type:
+ raise NotImplementedError(f'{type(self)}')
- def is_builtin(self) -> bool:
- return False
- def is_array(self) -> bool:
- return False
+class Modifier(AST2Node, ABC):
+ pass
- def is_byte_array(self) -> bool:
- return is_byte_array(self)
- def is_byte_array_underlying(self) -> bool:
- return self.is_byte_array() or self.is_string()
+@nodebase.NodeDataclass
+class ResolvedUserType(soltypes.Type):
+ scope: 'Scope' = field(default=None, init=False, repr=False, compare=False, hash=False)
+ # Ref so that we don't set the parent of the TopLevelUnit to this type instance
+ value: nodebase.Ref['TopLevelUnit'] = field(repr=False)
- def is_string(self) -> bool:
- return False
+ # FIXME: The name of the unit isn't showing in pretty prints for some reason, just outputs ResolvedUserType()
- def is_function(self) -> bool:
- return False
+ def __str__(self):
+ return f'ResolvedUserType({self.value.x.name.text})'
- def is_int(self) -> bool:
- return False
+ def __repr__(self):
+ return self.__str__()
- def is_bool(self) -> bool:
+ def is_builtin(self) -> bool:
return False
def is_user_type(self) -> bool:
- return False
-
- def is_address(self) -> bool:
- return False
+ return True
- def is_mapping(self) -> bool:
- return False
+ def can_implicitly_cast_from(self, actual_type: soltypes.Type) -> bool:
+ if super().can_implicitly_cast_from(actual_type):
+ return True
- def is_byte(self) -> bool:
- return False
+ if actual_type.is_user_type():
+ return actual_type.value.x.is_subttype_of(self.value.x)
- def is_tuple(self) -> bool:
return False
- def is_literal_type(self) -> bool:
- return False
+ def get_types_for_declared_type(self) -> list['TopLevelUnit']:
+ return [self.value.x] + self.value.x.get_subtypes()
- def is_void(self) -> bool:
- return False
+ def code_str(self):
+ return self.value.x.name.text
- def type_key(self):
- return self.code_str()
+@nodebase.NodeDataclass
+class SuperType(soltypes.Type):
-@NodeDataclass
-class VoidType(Type):
- def is_void(self) -> bool:
- return True
+ declarer: nodebase.Ref[U['ContractDefinition', 'InterfaceDefinition']] = field(repr=False)
def is_builtin(self) -> bool:
- return True
-
- def code_str(self):
- return raiseNotPrintable()
-
-
-@NodeDataclass
-class Stmt(Node, ABC):
- pass
-
+ return False
-@NodeDataclass
-class Expr(Node, ABC):
- def type_of(self) -> Type:
- raise NotImplementedError(f'{type(self)}')
+ def get_types_for_declared_type(self) -> list['TopLevelUnit']:
+ # FIXME: return bases
+ return self.declarer.x.get_supers()
+ def code_str(self):
+ return str(self)
-@NodeDataclass
-class Modifier(Node, ABC):
- pass
+ def __str__(self):
+ return f'super({str(self.declarer.x.name)})'
-@NodeDataclass
+@nodebase.NodeDataclass
class VisibilityModifier(Modifier):
kind: solnodes1.VisibilityModifierKind
@@ -378,7 +112,7 @@ def code_str(self):
return str(self.kind.value)
-@NodeDataclass
+@nodebase.NodeDataclass
class MutabilityModifier(Modifier):
kind: solnodes1.MutabilityModifierKind
@@ -386,34 +120,34 @@ def code_str(self):
return str(self.kind.value)
-@NodeDataclass
+@nodebase.NodeDataclass
class OverrideSpecifier(Modifier):
- bases: List['ResolvedUserType']
+ bases: list[ResolvedUserType]
def code_str(self):
return f'override' + f'({", ".join(b.code_str() for b in self.bases)})' if self.bases else ''
-@NodeDataclass
+@nodebase.NodeDataclass
class SuperConstructorInvocationModifier(Modifier):
- base_ttype: 'ResolvedUserType'
- inputs: List[Expr]
+ base_ttype: ResolvedUserType
+ inputs: list[Expr]
def code_str(self):
return f'{self.base_ttype.code_str()}({", ".join(e.code_str() for e in self.inputs)})'
-@NodeDataclass
+@nodebase.NodeDataclass
class FunctionInvocationModifier(Modifier):
- modifier: Ref['ModifierDefinition']
- inputs: List[Expr]
+ modifier: nodebase.Ref['ModifierDefinition']
+ inputs: list[Expr]
def code_str(self):
return f'{self.modifier.x.name.code_str()}({", ".join(e.code_str() for e in self.inputs)})'
-@NodeDataclass
-class Ident(Node):
+@nodebase.NodeDataclass
+class Ident(AST2Node):
text: str
def code_str(self):
@@ -423,8 +157,8 @@ def __str__(self):
return self.text
-@NodeDataclass
-class NamedArgument(Node):
+@nodebase.NodeDataclass
+class NamedArgument(AST2Node):
name: Ident
expr: Expr
@@ -432,8 +166,8 @@ def code_str(self):
return f'{self.name.code_str()}: {self.expr.code_str()}'
-@NodeDataclass
-class TopLevelUnit(Node, ABC):
+@nodebase.NodeDataclass
+class TopLevelUnit(AST2Node, ABC):
source_unit_name: str
name: Ident
@@ -452,14 +186,14 @@ def is_subttype_of(self, other_contract: 'TopLevelUnit') -> bool:
return False
def as_type(self):
- return ResolvedUserType(Ref(self))
+ return ResolvedUserType(nodebase.Ref(self))
- def get_supers(self) -> List[Union['ContractDefinition', 'InterfaceDefinition']]:
+ def get_supers(self) -> list[U['ContractDefinition', 'InterfaceDefinition']]:
# c.inherits are the InheritSpecifics
# s.name is the ResolvedUserType => .value.x is the Contract/InterfaceDefinition
return [s.name.value.x for s in self.inherits] if hasattr(self, 'inherits') else []
- def get_subtypes(self) -> List[Union['ContractDefinition', 'InterfaceDefinition']]:
+ def get_subtypes(self) -> list[U['ContractDefinition', 'InterfaceDefinition']]:
return [s.x for s in self._subtypes] if hasattr(self, '_subtypes') else []
def is_enum(self) -> bool:
@@ -477,9 +211,6 @@ def is_interface(self) -> bool:
def is_udvt(self) -> bool:
return isinstance(self, UserDefinedValueTypeDefinition)
- def is_enum(self) -> bool:
- return isinstance(self, EnumDefinition)
-
def find_named_parts(self, name: str, explore_mro: bool, matching_types):
results = []
for p in self.parts:
@@ -495,510 +226,126 @@ def find_named_parts(self, name: str, explore_mro: bool, matching_types):
return results
-@NodeDataclass
-class ArrayType(Type):
- """ Single dimension array type with no size attributes
- This is most often used for 'bytes' which is a array of bytes of unknown/variable length
- """
- base_type: Type
-
- def __str__(self): return f"{self.base_type}[]"
-
- def is_builtin(self) -> bool:
- # e.g. byte[] is builtin, string[] is builtin, MyContract[] is not
- return self.base_type.is_builtin()
-
- def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
- if super().can_implicitly_cast_from(actual_type):
- return True
- if not self.has_size() and actual_type.is_array() and actual_type.has_size():
- # i.e. FixedLengthArrayType/VariableLengthArrayType can cast to the base ArrayType (but not each other)
- # e.g. byte[4] casts to byte[] but not the other way around
- return self.base_type.can_implicitly_cast_from(actual_type.base_type)
- if self.base_type.is_byte() and not self.has_size() and actual_type.is_literal_type():
- if self.is_string() == actual_type.is_string():
- return True
- if self.is_int() == actual_type.is_int():
- return True
-
- return False
-
- def has_size(self) -> bool:
- return hasattr(self, 'size')
-
- def is_fixed_size(self) -> bool:
- return False
-
- def is_array(self) -> bool:
- return True
-
- def code_str(self):
- return f'{self.base_type.code_str()}[]'
-
-
-@NodeDataclass
-class FixedLengthArrayType(ArrayType):
- """ Array type with a known length that is determined at compile time """
- size: int
-
- def __str__(self): return f"{self.base_type}[{self.size}]"
-
- def is_fixed_size(self) -> bool:
- return True
-
- def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
- if super().can_implicitly_cast_from(actual_type):
- return True
- if not self.is_string() and self.base_type.is_byte() and actual_type.is_int() and actual_type.is_literal_type():
- # Decimal number literals cannot be implicitly converted to fixed-size byte arrays. Hexadecimal number literals
- # can be, but only if the number of hex digits exactly fits the size of the bytes type. As an exception both
- # decimal and hexadecimal literals which have a value of zero can be converted to any fixed-size bytes type:
- return self.size >= (actual_type.size / 8)
- if self.base_type.is_byte() and actual_type.is_string() and actual_type.is_literal_type():
- # e.g. bytes32 samevar = "stringliteral"
- return self.size >= actual_type.real_size
-
- return False
-
- def code_str(self):
- return f'{self.base_type.code_str()}[{str(self.size)}]'
-
-
-@NodeDataclass
-class VariableLengthArrayType(ArrayType):
- """ Array type with a length that is determined at runtime"""
- size: Expr
-
- def __str__(self): return f"{self.base_type}[{self.size}]"
-
- def code_str(self):
- return f'{self.base_type.code_str()}[{self.size.code_str()}]'
-
-
-@NodeDataclass
-class AddressType(Type):
- """ Solidity address/address payable type, functionally this is a uint160"""
- is_payable: bool
-
- def __str__(self): return f"address{' payable' if self.is_payable else ''}"
-
- def can_implicitly_cast_from(self, actual_type: Type) -> bool:
- # address_payable(actual_type) can be cast to address implicitly
- if actual_type.is_address():
- # Matrix:
- # self <= actual_type = can_implicitly_cast_from
- # AP <= AP = true
- # AP <= A = false
- # A <= A = true
- # A <= AP = true
- return not(self.is_payable and not actual_type.is_payable)
- # contracts can get cast to address (at least in solidity 0.4.23)
- if actual_type.is_user_type():
- definition = actual_type.value.x
- if definition.is_contract() or definition.is_interface():
- return True
- # uint160 can cast to address, I've seen this in a contract but AfterObol.sol:
- # _mint(0x0CA5cD5790695055F0a01F73A47160C35f9d3A46, 100000000 * 10 ** decimals());
- # but not sure how this is allowed exactly
- # UPDATE:
- # "Hexadecimal literals that pass the address checksum test, for example
- # 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF are of address type. Hexadecimal literals that are between 39 and
- # 41 digits long and do not pass the checksum test produce an error. You can prepend (for integer types) or
- # append (for bytesNN types) zeros to remove the error."
- # We can't do a check for hex literals (without changing some parsing code) just do it for any int
- if not self.is_payable and actual_type.is_int() and not actual_type.is_signed and actual_type.size == 160:
- return True
-
- return False
-
- def is_builtin(self) -> bool:
- return True
-
- def is_address(self) -> bool:
- return True
-
- def code_str(self):
- return 'address' + (' payable' if self.is_payable else '')
-
-
-@NodeDataclass
-class ByteType(Type):
- """ Single 8bit byte type """
-
- def __str__(self): return "byte"
-
- def is_builtin(self) -> bool:
- return True
-
- def is_byte(self) -> bool:
- return True
-
- def code_str(self):
- return 'byte'
-
-
-@NodeDataclass
-class BytesType(ArrayType):
- """ bytes type only (similar but not equal to byte[]/bytes1[]) """
- base_type: Type = field(default_factory=lambda: Bytes(1), init=False)
-
- def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
- # don't have anything in AST1 to mark whether the literal is a hex or dec int so we do the
- # conversion regardless
- # e.g. bytes public c = hex"11"; is allowed but bytes public c = 0x11; is NOT
- if actual_type.is_literal_type() and actual_type.is_int():
- return True
- return super().can_implicitly_cast_from(actual_type)
-
- def __str__(self):
- return self.code_str()
-
- def code_str(self):
- return 'bytes'
-
-
-@NodeDataclass
-class IntType(Type):
- """ Solidity native integer type of various bit length and signedness"""
-
- is_signed: bool
- """ Whether the type is a signed int or unsigned int """
- size: int
- """ Size of the type in bits """
-
- def __str__(self): return f"{'int' if self.is_signed else 'uint'}{self.size}"
-
- def can_implicitly_cast_from(self, actual_type: Type) -> bool:
- if actual_type.is_int():
- # inty(actual_type) to intx(self) if y <= x, same for uint, but not both at the same time
- if actual_type.is_signed == self.is_signed and actual_type.size <= self.size:
- return True
-
- if actual_type.is_int() and actual_type.is_literal_type() and not actual_type.is_signed:
- # e.g. calling f(1 :: uint8) where f(x: int256)
- return actual_type.real_bit_length < self.size
- return False
-
- def is_builtin(self) -> bool:
- return True
-
- def is_int(self) -> bool:
- return True
-
- def code_str(self):
- return ('u' if not self.is_signed else '') + 'int' + str(self.size)
-
-
-@NodeDataclass
-class PreciseIntType(IntType):
- real_bit_length: int
-
- def is_literal_type(self) -> bool:
- return True
-
- def __str__(self): return f"{'int' if self.is_signed else 'uint'}{self.size}({self.real_bit_length})"
-
- def code_str(self):
- return raiseNotPrintable()
-
-
-class BoolType(Type):
- """ Solidity native boolean type"""
-
- def __str__(self): return "bool"
-
- def is_builtin(self) -> bool:
- return True
-
- def is_bool(self) -> bool:
- return True
-
- def code_str(self):
- return 'bool'
-
-
-@NodeDataclass
-class StringType(ArrayType):
- """ Solidity native string type"""
-
- # makes this an Array[Byte] (as Solidity uses UTF8 for strings?)
- base_type: Type = field(default_factory=lambda: Bytes(1), init=False)
-
- def __str__(self): return "string"
-
- def is_builtin(self) -> bool:
- return True
-
- def is_string(self) -> bool:
- return True
-
- def code_str(self):
- return 'string'
-
-
-@NodeDataclass
-class PreciseStringType(StringType):
- """String literal type that has a known length at compile time"""
-
- real_size: int
-
- def is_literal_type(self) -> bool:
- return True
-
- def has_size(self) -> bool:
- # ArrayType.has_size() checks if we have a 'size' attribute, but we don't: it's called
- # real_size(), so this shim fixes that.
- # This allows e.g. PreciseStringType of length 1 to be implicitly castable to the base StringType
- return True
-
- def __str__(self): return f"string({self.real_size})"
-
- def code_str(self):
- return raiseNotPrintable()
-
-
-@NodeDataclass
-class MappingType(Type):
- """ Type that represents a function mapping definition
-
- For example in the mapping '(uint => Campaign)', src would be 'unit' and the dst would be 'Campaign'
- """
- src: Type
- dst: Type
-
- def __str__(self): return f"({self.src} => {self.dst})"
-
- def is_builtin(self) -> bool:
- return False
-
- def is_mapping(self) -> bool:
- return True
-
- def flatten(self) -> List[Type]:
- # get a nested mapping types elements in a list
- # e.g. (x => (y => z)) would return [x,y,z]
- result = [self.src]
- next_link = self.dst
- while next_link:
- if next_link.is_mapping():
- result.append(next_link.src)
- next_link = next_link.dst
- else:
- # base case, we hit the end of the chain
- result.append(next_link)
- next_link = None
- return result
-
- def code_str(self):
- return f"({self.src} => {self.dst})"
-
-
-@NodeDataclass
-class ResolvedUserType(Type):
- # Ref so that we don't set the parent of the TopLevelUnit to this type instance
- value: Ref[TopLevelUnit] = field(repr=False)
-
- # FIXME: The name of the unit isn't showing in pretty prints for some reason, just outputs ResolvedUserType()
-
- def __str__(self):
- return f'ResolvedUserType({self.value.x.name.text})'
-
- def __repr__(self):
- return self.__str__()
-
- def is_builtin(self) -> bool:
- return False
-
- def is_user_type(self) -> bool:
- return True
-
- def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
- if super().can_implicitly_cast_from(actual_type):
- return True
-
- if actual_type.is_user_type():
- return actual_type.value.x.is_subttype_of(self.value.x)
-
- return False
-
- def get_types_for_declared_type(self) -> List[TopLevelUnit]:
- return [self.value.x] + self.value.x.get_subtypes()
-
- def code_str(self):
- return self.value.x.name.text
-
-
-@NodeDataclass
-class BuiltinType(Type):
- name: str
-
- def __str__(self):
- return f'Builtin<{self.name}>'
-
- def is_builtin(self) -> bool:
- return True
-
- def code_str(self):
- return self.name
-
-
-def ABIType() -> BuiltinType:
- return BuiltinType('abi')
-
-
-@NodeDataclass
-class FunctionType(Type):
- inputs: List[Type]
- outputs: List[Type]
-
- def is_builtin(self) -> bool:
- return False
-
- def is_function(self) -> bool:
- return True
-
- def code_str(self):
- # function () {internal|external} [pure|view|payable] [returns ()]
- return f'function ({", ".join(t.code_str() for t in self.inputs)}) returns ({", ".join(t.code_str() for t in self.outputs)})'
-
- def type_key(self):
- # doesn't include modifiers for now
- input_params = ', '.join([p.type_key() for p in self.inputs])
- output_params = ', '.join([p.type_key() for p in self.outputs])
- return f'function ({input_params}) returns ({output_params})'
-
-@NodeDataclass
-class TupleType(Type):
- ttypes: List[Type]
-
- def is_builtin(self) -> bool:
- return False
-
- def is_tuple(self) -> bool:
- return True
-
- def code_str(self):
- return f'({", ".join(t.code_str() for t in self.ttypes)})'
-
-
-@NodeDataclass
-class ContractPart(Node, ABC):
- def has_modifier_kind(self, *kinds: Union[solnodes1.VisibilityModifierKind, solnodes1.MutabilityModifierKind]):
+@nodebase.NodeDataclass
+class ContractPart(AST2Node, ABC):
+ def has_modifier_kind(self, *kinds: solnodes1.VisibilityModifierKind | solnodes1.MutabilityModifierKind):
return solnodes1.has_modifier_kind(self, *kinds)
-@NodeDataclass
-class InheritSpecifier(Node):
+@nodebase.NodeDataclass
+class InheritSpecifier(AST2Node):
name: ResolvedUserType
- args: List[Expr]
+ args: list[Expr]
def code_str(self):
return self.name.code_str() + f'({", ".join(e.code_str() for e in self.args)})'
-@NodeDataclass
-class LibraryOverride(Node):
- overriden_type: Type
+@nodebase.NodeDataclass
+class LibraryOverride(AST2Node):
+ overriden_type: soltypes.Type
library: ResolvedUserType
-@NodeDataclass
+@nodebase.NodeDataclass
class FileDefinition(TopLevelUnit):
# This is currently only used for ownerless definitions, i.e. contracts/interfaces/etc don't have this as a parent
# and this isn't created for most processed source files
- parts: List[ContractPart]
+ scope: 'Scope' = field(default=None, init=False, repr=False, compare=False, hash=False)
+ parts: list[ContractPart]
-@NodeDataclass
+@nodebase.NodeDataclass
class ContractDefinition(TopLevelUnit):
is_abstract: bool
- inherits: List[InheritSpecifier]
- parts: List[ContractPart]
- type_overrides: List[LibraryOverride]
- _subtypes: List[Ref[Union['ContractDefinition', 'InterfaceDefinition']]] = field(default_factory=list, init=False, hash=False, compare=False, repr=False)
+ inherits: list[InheritSpecifier]
+ parts: list[ContractPart]
+ type_overrides: list[LibraryOverride]
+ _subtypes: list[nodebase.Ref[U['ContractDefinition', 'InterfaceDefinition']]] = field(default_factory=list, init=False, hash=False, compare=False, repr=False)
-@NodeDataclass
+@nodebase.NodeDataclass
class InterfaceDefinition(TopLevelUnit):
- inherits: List[InheritSpecifier]
- parts: List[ContractPart]
- type_overrides: List[LibraryOverride]
- _subtypes: List[Ref[Union['ContractDefinition', 'InterfaceDefinition']]] = field(default_factory=list, init=False, hash=False, compare=False, repr=False)
+ inherits: list[InheritSpecifier]
+ parts: list[ContractPart]
+ type_overrides: list[LibraryOverride]
+ _subtypes: list[nodebase.Ref[U['ContractDefinition', 'InterfaceDefinition']]] = field(default_factory=list, init=False, hash=False, compare=False, repr=False)
-@NodeDataclass
+@nodebase.NodeDataclass
class LibraryDefinition(TopLevelUnit):
- parts: List[ContractPart]
- type_overrides: List[LibraryOverride]
+ parts: list[ContractPart]
+ type_overrides: list[LibraryOverride]
-@NodeDataclass
+@nodebase.NodeDataclass
class UserDefinedValueTypeDefinition(TopLevelUnit):
- ttype: Type
+ ttype: soltypes.Type
-@NodeDataclass
-class EnumMember(Node):
+@nodebase.NodeDataclass
+class EnumMember(AST2Node):
name: Ident
-@NodeDataclass
+@nodebase.NodeDataclass
class EnumDefinition(TopLevelUnit):
- values: List[EnumMember]
+ values: list[EnumMember]
-@NodeDataclass
-class StructMember(Node):
- ttype: Type
+@nodebase.NodeDataclass
+class StructMember(AST2Node):
+ ttype: soltypes.Type
name: Ident
-@NodeDataclass
+@nodebase.NodeDataclass
class StructDefinition(TopLevelUnit):
- members: List[StructMember]
+ members: list[StructMember]
-@NodeDataclass
-class ErrorParameter(Node):
- ttype: Type
+@nodebase.NodeDataclass
+class ErrorParameter(AST2Node):
+ ttype: soltypes.Type
name: Ident
-@NodeDataclass
+@nodebase.NodeDataclass
class ErrorDefinition(ContractPart):
name: Ident
- inputs: List[ErrorParameter]
+ inputs: list[ErrorParameter]
-@NodeDataclass
+@nodebase.NodeDataclass
class StateVariableDeclaration(ContractPart):
name: Ident
- ttype: Type
- modifiers: List[Modifier]
+ ttype: soltypes.Type
+ modifiers: list[Modifier]
value: Expr
-@NodeDataclass
+@nodebase.NodeDataclass
class ConstantVariableDeclaration(ContractPart):
name: Ident
- ttype: Type
+ ttype: soltypes.Type
value: Expr
-@NodeDataclass
-class EventParameter(Node):
+@nodebase.NodeDataclass
+class EventParameter(AST2Node):
name: Ident
- ttype: Type
+ ttype: soltypes.Type
is_indexed: bool
-@NodeDataclass
+@nodebase.NodeDataclass
class EventDefinition(ContractPart):
name: Ident
- inputs: List[EventParameter]
+ inputs: list[EventParameter]
is_anonymous: bool
+@nodebase.NodeDataclass
class Location(Enum):
MEMORY = 'memory'
STORAGE = 'storage'
@@ -1007,24 +354,24 @@ class Location(Enum):
def __str__(self): return self.value
-@NodeDataclass
-class Var(Node):
+@nodebase.NodeDataclass
+class Var(AST2Node):
name: Ident
- ttype: Type
+ ttype: soltypes.Type
location: Location
def code_str(self):
return raiseNotPrintable()
-@NodeDataclass
-class Parameter(Node):
+@nodebase.NodeDataclass
+class Parameter(AST2Node):
var: Var
-@NodeDataclass
+@nodebase.NodeDataclass
class Block(Stmt):
- stmts: List[Stmt]
+ stmts: list[Stmt]
is_unchecked: bool
def code_str(self, brackets=True):
@@ -1037,7 +384,7 @@ def code_str(self, brackets=True):
return indent('\n'.join(lines), INDENT)
-@NodeDataclass
+@nodebase.NodeDataclass
class If(Stmt):
condition: Expr
true_branch: Stmt
@@ -1066,10 +413,10 @@ def block_str(b):
return '\n'.join(lines)
-@NodeDataclass
+@nodebase.NodeDataclass
class Catch(Stmt):
ident: Ident
- parameters: List[Parameter]
+ parameters: list[Parameter]
body: Block
def code_str(self):
@@ -1093,12 +440,12 @@ def code_str(self):
return '\n'.join(lines)
-@NodeDataclass
+@nodebase.NodeDataclass
class Try(Stmt):
expr: Expr
- return_parameters: List[Parameter]
+ return_parameters: list[Parameter]
body: Block
- catch_clauses: List[Catch]
+ catch_clauses: list[Catch]
def code_str(self):
lines = [
@@ -1126,7 +473,7 @@ def code_str(self):
return '\n'.join(lines)
-@NodeDataclass
+@nodebase.NodeDataclass
class While(Stmt):
condition: Expr
body: Stmt
@@ -1157,7 +504,7 @@ def c_str(b):
return '\n'.join(lines)
-@NodeDataclass
+@nodebase.NodeDataclass
class For(Stmt):
initialiser: Stmt
condition: Expr
@@ -1188,14 +535,14 @@ class FunctionMarker(Enum):
SYNTHETIC_FIELD_GETTER = 2
-@NodeDataclass
+@nodebase.NodeDataclass
class FunctionDefinition(ContractPart):
name: Ident
- inputs: List[Parameter]
- outputs: List[Parameter]
- modifiers: List[Modifier]
+ inputs: list[Parameter]
+ outputs: list[Parameter]
+ modifiers: list[Modifier]
code: Block
- markers: List[FunctionMarker]
+ markers: list[FunctionMarker]
@staticmethod
def param_str(ps) -> str:
@@ -1209,23 +556,24 @@ def __str__(self):
return self.descriptor()
-@NodeDataclass
-class BuiltinFunction(Node):
+@nodebase.NodeDataclass
+class BuiltinFunction(AST2Node):
name: Ident
- inputs: List[Parameter]
- outputs: List[Parameter]
+ inputs: list[Parameter]
+ outputs: list[Parameter]
+
-@NodeDataclass
+@nodebase.NodeDataclass
class ModifierDefinition(ContractPart):
name: Ident
- inputs: List[Parameter]
- modifiers: List[Modifier]
+ inputs: list[Parameter]
+ modifiers: list[Modifier]
code: Block
-@NodeDataclass
+@nodebase.NodeDataclass
class TupleVarDecl(Stmt):
- vars: List[Var]
+ vars: list[Var]
value: Expr
def code_str(self):
@@ -1234,7 +582,7 @@ def code_str(self):
return f'({", ".join(vs)}){rhs}'
-@NodeDataclass
+@nodebase.NodeDataclass
class VarDecl(Stmt):
var: Var
value: Expr
@@ -1244,7 +592,7 @@ def code_str(self):
return f'{self.var.ttype.code_str()} {(self.var.location.value + " ") if self.var.location else ""}{self.var.name.text}{rhs};'
-@NodeDataclass
+@nodebase.NodeDataclass
class ExprStmt(Stmt):
expr: Expr
@@ -1252,13 +600,13 @@ def code_str(self):
return f'{self.expr.code_str()};'
-@NodeDataclass
+@nodebase.NodeDataclass
class Literal(Expr):
value: Any
- ttype: Type
+ ttype: soltypes.Type
unit: solnodes1.Unit = None
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
@@ -1268,9 +616,9 @@ def code_str(self):
return str(self.value)
-@NodeDataclass
+@nodebase.NodeDataclass
class TypeLiteral(Expr):
- ttype: Type
+ ttype: soltypes.Type
def type_of(self):
return self.ttype
@@ -1279,19 +627,19 @@ def code_str(self):
return self.ttype.code_str()
-@NodeDataclass
+@nodebase.NodeDataclass
class UnaryOp(Expr):
""" Single operand expression """
expr: Expr
op: solnodes1.UnaryOpCode
is_pre: bool
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
expr_ttype = self.expr.type_of()
if self.op == solnodes1.UnaryOpCode.BOOL_NEG:
assert expr_ttype.is_bool()
elif self.op == solnodes1.UnaryOpCode.BIT_NEG:
- assert is_byte_array(expr_ttype) or expr_ttype.is_int()
+ assert expr_ttype.is_byte_array() or expr_ttype.is_int()
elif self.op != solnodes1.UnaryOpCode.DELETE:
assert expr_ttype.is_int()
return expr_ttype
@@ -1303,19 +651,19 @@ def code_str(self):
return f'{self.expr.code_str()}{str(self.op.value)}'
-@NodeDataclass
+@nodebase.NodeDataclass
class BinaryOp(Expr):
left: Expr
right: Expr
op: solnodes1.BinaryOpCode
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
if self.op in [solnodes1.BinaryOpCode.BOOL_AND, solnodes1.BinaryOpCode.BOOL_OR, solnodes1.BinaryOpCode.EQ,
solnodes1.BinaryOpCode.NEQ]:
- return BoolType()
+ return soltypes.BoolType()
elif self.op in [solnodes1.BinaryOpCode.LTEQ, solnodes1.BinaryOpCode.LT, solnodes1.BinaryOpCode.GT,
solnodes1.BinaryOpCode.GTEQ]:
- return BoolType()
+ return soltypes.BoolType()
elif self.op in [solnodes1.BinaryOpCode.LSHIFT, solnodes1.BinaryOpCode.RSHIFT]:
# result of a shift has the type of the left operand (from docs)
return self.left.type_of()
@@ -1337,13 +685,13 @@ def code_str(self):
return f'{self.left.code_str()} {str(self.op.value)} {self.right.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class TernaryOp(Expr):
condition: Expr
left: Expr
right: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
t1 = self.left.type_of()
t2 = self.right.type_of()
@@ -1354,7 +702,7 @@ def type_of(self) -> Type:
return t1 if t1.size > t2.size else t2
elif t1.is_string() and t2.is_string():
# TODO: precise string vs non precise string? precise string(x) vs precise string (y)
- return StringType()
+ return soltypes.StringType()
else:
try:
assert t1 == t2, f'{t1} vs {t2}'
@@ -1373,49 +721,34 @@ def code_str(self):
return f'{self.condition.code_str()} ? {self.left.code_str()} : {self.right.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class SelfObject(Expr):
- declarer: Ref[Union[ContractDefinition, InterfaceDefinition]] = field(repr=False)
+ declarer: nodebase.Ref[ContractDefinition | InterfaceDefinition] = field(repr=False)
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return ResolvedUserType(self.declarer)
def code_str(self):
return 'this'
-@NodeDataclass
-class SuperType(Type):
- declarer: Ref[Union[ContractDefinition, InterfaceDefinition]] = field(repr=False)
-
- def is_builtin(self) -> bool:
- return False
-
- def get_types_for_declared_type(self) -> List[TopLevelUnit]:
- # FIXME: return bases
- return self.declarer.x.get_supers()
-
- def code_str(self):
- return raiseNotPrintable()
-
-
-@NodeDataclass
+@nodebase.NodeDataclass
class SuperObject(Expr):
ttype: SuperType
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return 'super'
-@NodeDataclass
+@nodebase.NodeDataclass
class StateVarLoad(Expr):
base: Expr
name: Ident
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
base_type = self.base.type_of()
assert isinstance(base_type, ResolvedUserType)
@@ -1434,12 +767,12 @@ def code_str(self):
return f'{self.base.code_str()}.{self.name.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class StaticVarLoad(Expr):
ttype: ResolvedUserType
name: Ident
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
unit = self.ttype.value.x
for p in unit.parts:
if p.name.text == self.name.text and isinstance(p, (StateVariableDeclaration, ConstantVariableDeclaration)):
@@ -1450,11 +783,11 @@ def code_str(self):
return f'{self.ttype.code_str()}.{self.name.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class EnumLoad(Expr):
- member: Ref[EnumMember]
+ member: nodebase.Ref[EnumMember]
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
# enum members type is its parent type
return self.member.x.parent.as_type()
@@ -1463,64 +796,64 @@ def code_str(self):
return f'{enum_def.name.code_str()}.{self.member.x.name.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class StateVarStore(Expr):
base: Expr
name: Ident
value: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.value.type_of()
def code_str(self):
return f'{self.base.code_str()}.{self.name.code_str()} = {self.value.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class LocalVarLoad(Expr):
var: Var
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.var.ttype
def code_str(self):
return self.var.name.code_str()
-@NodeDataclass
+@nodebase.NodeDataclass
class LocalVarStore(Expr):
var: Var
value: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.var.ttype
def code_str(self):
return f'{self.var.name.text} = {self.value.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class ArrayLengthStore(Expr):
# resizing array length is deprecated since solidity 0.6
# The expr that loads the array e.g. this.myArray
base: Expr
value: Expr
- def type_of(self) -> Type:
- return UIntType(256)
+ def type_of(self) -> soltypes.Type:
+ return soltypes.UIntType(256)
def code_str(self):
raise NotImplementedError()
-@NodeDataclass
+@nodebase.NodeDataclass
class TupleLoad(Expr):
base: Expr
index: int
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
tuple_type = self.base.type_of()
- assert isinstance(tuple_type, TupleType)
+ assert isinstance(tuple_type, soltypes.TupleType)
assert 0 <= self.index < len(tuple_type.ttypes)
@@ -1530,18 +863,18 @@ def code_str(self):
return f'{self.base.code_str()}[{self.index}]'
-@NodeDataclass
+@nodebase.NodeDataclass
class ArrayLoad(Expr):
base: Expr
index: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
base_type = self.base.type_of()
- if isinstance(base_type, MappingType):
+ if isinstance(base_type, soltypes.MappingType):
assert base_type.src.can_implicitly_cast_from(self.index.type_of())
return base_type.dst
- elif isinstance(base_type, ArrayType):
+ elif isinstance(base_type, soltypes.ArrayType):
assert self.index.type_of().is_int()
return base_type.base_type
else:
@@ -1551,27 +884,27 @@ def code_str(self):
return f'{self.base.code_str()}[{self.index.code_str()}]'
-@NodeDataclass
+@nodebase.NodeDataclass
class ArrayStore(Expr):
base: Expr
index: Expr
value: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return ArrayLoad.type_of(self)
def code_str(self):
return f'{self.base.code_str()}[{self.index.code_str()}] = {self.value.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class ArraySliceLoad(Expr):
""" Gets a subarray at the given start and end indices from the given array """
base: Expr
start_index: Expr
end_index: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.base.type_of()
def code_str(self):
@@ -1580,16 +913,16 @@ def code_str(self):
return f'{self.base.code_str()}[{start_str}:{end_str}]'
-@NodeDataclass
+@nodebase.NodeDataclass
class CreateInlineArray(Expr):
""" Solidity 8 inline array creation
An inline array is one where the elements are explicitly stated in the definition, for example:
'int[5] foo2 = [1, 0, 0, 0, 0];'
"""
- elements: List[Expr]
+ elements: list[Expr]
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
arg_types = [arg.type_of() for arg in self.elements]
are_ints = any([t.is_int() for t in arg_types])
@@ -1609,17 +942,17 @@ def type_of(self) -> Type:
if any([not t.is_literal_type() for t in arg_types]):
# if there are any non precise ones, the whole thing can't be precise, e.g. [0, 1, this.myInt] can't
# have a base_type of uint8(1), instead it must be uint(T(this.myInt))
- base_type = IntType(is_signed, max_total_length)
+ base_type = soltypes.IntType(is_signed, max_total_length)
else:
- base_type = PreciseIntType(is_signed, max_total_length, max_real_bit_length)
+ base_type = soltypes.PreciseIntType(is_signed, max_total_length, max_real_bit_length)
- return FixedLengthArrayType(base_type, len(self.elements))
+ return soltypes.FixedLengthArrayType(base_type, len(self.elements))
def code_str(self):
return f'[{", ".join(e.code_str() for e in self.elements)}]'
-@NodeDataclass
+@nodebase.NodeDataclass
class MappingLoad(Expr):
base: Expr
key: Expr
@@ -1627,11 +960,12 @@ class MappingLoad(Expr):
def code_str(self):
return f'{self.base.code_str()}[{self.key.code_str()}]'
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
base_ttype = self.base.type_of()
return base_ttype.dst
-@NodeDataclass
+
+@nodebase.NodeDataclass
class MappingStore(Expr):
base: Expr
key: Expr
@@ -1641,30 +975,30 @@ def code_str(self):
return f'{self.base.code_str()}[{self.key.code_str()}] = {self.value.code_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class GlobalValue(Expr):
name: str
- ttype: Type
+ ttype: soltypes.Type
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return self.name
-@NodeDataclass
+@nodebase.NodeDataclass
class ABISelector(Expr):
- function: Union[Ref[Union[FunctionDefinition, ErrorDefinition]], Expr]
+ function: nodebase.Ref[FunctionDefinition | ErrorDefinition] | Expr
- def type_of(self) -> Type:
- return Bytes(4)
+ def type_of(self) -> soltypes.Type:
+ return soltypes.Bytes(4)
def __str__(self):
return self.code_str()
def code_str(self):
- if isinstance(self.function, Ref):
+ if isinstance(self.function, nodebase.Ref):
f = self.function.x
owner_name = f.parent.source_unit_name
return f'{owner_name}.{f.name.text}.selector'
@@ -1672,73 +1006,73 @@ def code_str(self):
return f'{self.function.code_str()}.selector'
-@NodeDataclass
+@nodebase.NodeDataclass
class DynamicBuiltInValue(Expr):
# .name
name: str
- ttype: Type
+ ttype: soltypes.Type
base: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return f'{self.base.code_str()}.{self.name}'
-@NodeDataclass
+@nodebase.NodeDataclass
class CreateMemoryArray(Expr):
- ttype: ArrayType
+ ttype: soltypes.ArrayType
size: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return f'new {self.ttype.code_str()}[{self.size.code_str()}]'
-@NodeDataclass
+@nodebase.NodeDataclass
class CreateStruct(Expr):
ttype: ResolvedUserType
- args: List[Expr]
+ args: list[Expr]
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return f'{self.ttype.code_str()}({", ".join(e.code_str() for e in self.args)})'
-@NodeDataclass
+@nodebase.NodeDataclass
class CreateAndDeployContract(Expr):
ttype: ResolvedUserType
- named_args: List[NamedArgument]
- args: List[Expr]
+ named_args: list[NamedArgument]
+ args: list[Expr]
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return f"new {self.ttype.code_str()}" + Call.param_str(self)
-@NodeDataclass
+@nodebase.NodeDataclass
class Call(Expr, ABC):
- named_args: List[NamedArgument]
- args: List[Expr]
+ named_args: list[NamedArgument]
+ args: list[Expr]
def check_arg_types(self, f: FunctionDefinition) -> bool:
f_types = [x.var.ttype for x in f.inputs]
c_types = [a.type_of() for a in self.args]
- return Type.are_matching_types(f_types, c_types)
+ return soltypes.Type.are_matching_types(f_types, c_types)
def param_str(self):
return ('{' + ', '.join(e.code_str() for e in self.named_args) + '}') if hasattr(self, 'named_args') and len(
self.named_args) > 0 else '' + f'({", ".join(e.code_str() for e in self.args)})'
-@NodeDataclass
+@nodebase.NodeDataclass
class DirectCall(Call):
ttype: ResolvedUserType
name: Ident
@@ -1753,13 +1087,13 @@ def resolve_call(self) -> FunctionDefinition:
assert len(matching_param_types) == 1
return matching_param_types[0]
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
target_callee = self.resolve_call()
if not target_callee.outputs:
- ttype = VoidType()
+ ttype = soltypes.VoidType()
elif len(target_callee.outputs) > 1:
# For functions that return multiple values return (t(r1), ... t(rk))
- ttype = TupleType([out_param.var.ttype for out_param in target_callee.outputs])
+ ttype = soltypes.TupleType([out_param.var.ttype for out_param in target_callee.outputs])
else:
ttype = target_callee.outputs[0].var.ttype
return ttype
@@ -1770,8 +1104,8 @@ def code_str(self):
def __str__(self):
return f'"{self.code_str()}"'
-# x.y
-@NodeDataclass
+
+@nodebase.NodeDataclass
class FunctionCall(Call):
base: Expr
name: Ident
@@ -1798,13 +1132,13 @@ def resolve_call(self) -> FunctionDefinition:
raise ValueError('No match')
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
target_callee = self.resolve_call()
if not target_callee.outputs:
- ttype = VoidType()
+ ttype = soltypes.VoidType()
elif len(target_callee.outputs) > 1:
# For functions that return multiple values return (t(r1), ... t(rk))
- ttype = TupleType([out_param.var.ttype for out_param in target_callee.outputs])
+ ttype = soltypes.TupleType([out_param.var.ttype for out_param in target_callee.outputs])
else:
ttype = target_callee.outputs[0].var.ttype
return ttype
@@ -1815,126 +1149,115 @@ def code_str(self):
def __str__(self):
return f'"{self.code_str()}"'
-@NodeDataclass
+
+@nodebase.NodeDataclass
class FunctionPointerCall(Call):
callee: Expr
- def type_of(self) -> Type:
- callee_ttype: FunctionType = self.callee.type_of()
+ def type_of(self) -> soltypes.Type:
+ callee_ttype: soltypes.FunctionType = self.callee.type_of()
output_ttypes = callee_ttype.outputs
assert len(output_ttypes) > 0
if not output_ttypes:
- return VoidType()
+ return soltypes.VoidType()
elif len(output_ttypes) == 1:
return output_ttypes[0]
else:
- return TupleType(output_ttypes)
+ return soltypes.TupleType(output_ttypes)
def code_str(self):
return f'{self.callee.code_str()}{self.param_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class DynamicBuiltInCall(Call):
- ttype: Type
- base: Union[Expr, ResolvedUserType]
+ ttype: soltypes.Type
+ base: Expr | ResolvedUserType
name: str
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return f'{self.base.code_str()}.{self.name}{self.param_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class BuiltInCall(Call):
name: str
- ttype: Type
+ ttype: soltypes.Type
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return f'{self.name}{self.param_str()}'
-@NodeDataclass
+@nodebase.NodeDataclass
class Cast(Expr):
- ttype: Type
+ ttype: soltypes.Type
value: Expr
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
return self.ttype
def code_str(self):
return f'{self.ttype.code_str()}({self.value.code_str()})'
-@NodeDataclass
-class MetaTypeType(Type):
- # type of a Solidity type, i.e. the type of type(X). This type has a few builtin fields such as min, max, name,
- # creationCode, runtimeCode and interfaceId
- ttype: Type
-
- def is_builtin(self) -> bool:
- return self.ttype.is_builtin()
-
- def code_str(self):
- return raiseNotPrintable()
-
-
-@NodeDataclass
+@nodebase.NodeDataclass
class GetType(Expr):
# type(MyContract)
- ttype: Type
+ ttype: soltypes.Type
- def type_of(self) -> Type:
- return MetaTypeType(self.ttype)
+ def type_of(self) -> soltypes.Type:
+ return soltypes.MetaTypeType(self.ttype)
def code_str(self):
return f'type({self.ttype.code_str()})'
-@NodeDataclass
+@nodebase.NodeDataclass
class GetFunctionPointer(Expr):
- func: Ref[Union[FunctionDefinition, 'BuiltinFunction']]
+ func: nodebase.Ref[U[FunctionDefinition, 'BuiltinFunction']]
- def type_of(self) -> Type:
+ def type_of(self) -> soltypes.Type:
def ts(params):
return [p.var.ttype for p in params]
f = self.func.x
- return FunctionType(ts(f.inputs), ts(f.outputs))
+ modifiers = f.modifiers if hasattr(f, 'modifiers') else []
+ return soltypes.FunctionType(ts(f.inputs), ts(f.outputs), modifiers)
def code_str(self):
return f'fptr({self.func.x.parent.descriptor()}::{self.func.x.name.text})'
-@NodeDataclass
+@nodebase.NodeDataclass
class EmitEvent(Stmt):
- event: Ref[EventDefinition]
- args: List[Expr]
+ event: nodebase.Ref[EventDefinition]
+ args: list[Expr]
def code_str(self):
return f'emit {self.event.x.name.text}{Call.param_str(self)}'
-@NodeDataclass
+@nodebase.NodeDataclass
class Revert(Stmt):
pass
-@NodeDataclass
+@nodebase.NodeDataclass
class RevertWithError(Revert):
- error: Ref[ErrorDefinition]
- args: List[Expr]
+ error: nodebase.Ref[ErrorDefinition]
+ args: list[Expr]
def code_str(self):
return f'revert {self.error.x.name.text}({", ".join(e.code_str() for e in self.args)});'
-@NodeDataclass
+@nodebase.NodeDataclass
class RevertWithReason(Revert):
reason: Expr
@@ -1942,7 +1265,7 @@ def code_str(self):
return f'revert({self.reason.code_str()});'
-@NodeDataclass
+@nodebase.NodeDataclass
class Require(Stmt):
condition: Expr
reason: Expr
@@ -1951,27 +1274,27 @@ def code_str(self):
return f'require({self.condition.code_str()}{(", " + self.reason.code_str()) if self.reason else ""})'
-@NodeDataclass
+@nodebase.NodeDataclass
class Return(Stmt):
- values: List[Expr]
+ values: list[Expr]
def code_str(self):
return f'return {", ".join([v.code_str() for v in self.values])}'
-@NodeDataclass
+@nodebase.NodeDataclass
class Continue(Stmt):
def code_str(self):
return 'continue;'
-@NodeDataclass
+@nodebase.NodeDataclass
class Break(Stmt):
def code_str(self):
return 'break;'
-@NodeDataclass
+@nodebase.NodeDataclass
class Assembly(Stmt):
# TODO: full assembly code representation
code: str
@@ -1980,13 +1303,20 @@ def code_str(self):
return f'assembly {{{self.code}}}'
-@NodeDataclass
+@nodebase.NodeDataclass
class ExecModifiedCode(Stmt):
# _; statement in modifier code bodies that show where modified function code gets executed
pass
-@NodeDataclass
+@nodebase.NodeDataclass
class UnprocessedCode(Stmt):
error: Exception = field(repr=False, hash=False, compare=False)
+
+Types: TypeAlias = (soltypes.VariableLengthArrayType | soltypes.VoidType | soltypes.IntType
+ | soltypes.FunctionType | soltypes.ArrayType | soltypes.BytesType | soltypes.BoolType
+ | soltypes.AnyType | soltypes.MappingType | soltypes.StringType | soltypes.AddressType
+ | soltypes.FixedLengthArrayType | soltypes.ByteType | soltypes.MetaTypeType
+ | soltypes.TupleType | soltypes.PreciseIntType | soltypes.PreciseIntType
+ | soltypes.BuiltinType | ResolvedUserType | SuperType | soltypes.FloatType)
diff --git a/src/solidity_parser/ast/symtab.py b/src/solidity_parser/ast/symtab.py
index 491b75f..b61bea0 100644
--- a/src/solidity_parser/ast/symtab.py
+++ b/src/solidity_parser/ast/symtab.py
@@ -1,27 +1,25 @@
-from dataclasses import dataclass, field
-from typing import Union, List, Dict, Optional, Type, Tuple, Set, Collection, Callable
+from typing import Union, Dict, Optional, Type, Tuple, Set, Collection, TypeAlias, Callable, TypeVar, cast, overload, Literal
from collections import defaultdict
from enum import Enum
-from solidity_parser.ast import solnodes
+from solidity_parser.ast import solnodes, types as soltypes, nodebase
from solidity_parser.filesys import LoadedSource, VirtualFileSystem
from solidity_parser.ast.mro_helper import c3_linearise
-import solidity_parser.errors as errors
import logging
import solidity_parser.util.version_util as version_util
-Aliases = Union[str, List[str]]
+Aliases: TypeAlias = str | list[str]
def bytes():
- return solnodes.BytesType()
+ return soltypes.Bytes()
def bytesn(n):
- return solnodes.FixedLengthArrayType(solnodes.ByteType(), n)
+ return soltypes.Bytes(n)
def bytes32():
@@ -29,7 +27,7 @@ def bytes32():
def uint(size=256):
- return solnodes.IntType(False, size)
+ return soltypes.UIntType(size)
def ACCEPT(x):
@@ -53,7 +51,7 @@ def do_test(x: 'Symbol'):
return do_test
-def is_top_level(node: solnodes.Node):
+def is_top_level(node: nodebase.Node):
# Error and FunctionDefinitions are set as SourceUnits in AST1 but not in AST2
return isinstance(node, (solnodes.ContractDefinition, solnodes.InterfaceDefinition, solnodes.LibraryDefinition,
solnodes.EnumDefinition, solnodes.UserValueType, solnodes.StructDefinition))
@@ -111,7 +109,7 @@ def test_predicate(xs, predicate=None):
return [x for x in xs if predicate(x)]
-def _add_to_results(possible_symbols: Collection, results: List, found_already: Set):
+def _add_to_results(possible_symbols: Collection, results: list, found_already: Set):
for s in possible_symbols:
res_syms = s.get_as_dealiased_symbols()
for base_s in res_syms:
@@ -132,23 +130,42 @@ def __init__(self, aliases: Optional[Aliases]):
elif not isinstance(aliases, list):
aliases = [aliases]
- self.aliases: List[str] = aliases
+ self.aliases: list[str] = aliases
def set_parent_scope(self, parent_scope: 'Scope'):
+ """ Sets the parent scope of this element, subclasses can check the type of the parent for sanity checks """
assert self.parent_scope is None, 'Element is already scoped'
self.parent_scope = parent_scope
- def find_first_ancestor(self, predicate, get_parent=None):
- """Walks up the symbol tree and finds the first element that satisfies the given predicate"""
+ _T = TypeVar('_T', bound='Scopeable')
+
+ def find_first_ancestor(self, predicate: Callable[['Scopeable'], bool], get_parent: Optional[Callable[['Scopeable'], 'Scope']] = None) -> Optional[_T]:
+ """
+ Walks up the symbol tree and finds the first element that satisfies the given predicate
+
+ :param predicate: a function that takes a Scopeable and returns a bool to determine if it matches
+ :param get_parent: a function that takes a Scopeable and returns its parent, defaults to the parent_scope of a
+ Scopeable
+ :return: the first Scopeable that satisfies the predicate
+ """
if get_parent is None:
get_parent = lambda x: x.parent_scope
+ # current can be a non Scope Scopeable, e.g. a Symbol only and depending on the predicate it can return a Symbol
+ # insted of Scope, however, usually the predicate is checking for something that is a Scope and a Symbol at the
+ # same time
current = self
while current and not predicate(current):
current = get_parent(current)
return current
- def find_first_ancestor_of(self, ttype: Union[Type, Tuple[Type]]):
+ def find_first_ancestor_of(self, ttype: Type[_T]) -> Optional[_T]:
+ """
+ Find the first ancestor that is of the given type, note: these are python types and not solc types.
+
+ :param ttype: e.g. ContractOrInterfaceScope
+ :return: the first ancestor that is of the given type
+ """
return self.find_first_ancestor(lambda x: isinstance(x, ttype))
def _check_single_symbol(self, name, results, default):
@@ -172,10 +189,10 @@ def __init__(self, aliases: Optional[Aliases], value):
self.value = value
self.order = -1
- def get_as_dealiased_symbols(self) -> List['Symbol']:
+ def get_as_dealiased_symbols(self) -> list['Symbol']:
return [self]
- def res_syms(self) -> List['Symbol']:
+ def res_syms(self) -> list['Symbol']:
# Return the symbols this symbol points to, if any exist.
return [self]
@@ -199,10 +216,10 @@ def __init__(self, aliases: Aliases, other_symbol: Symbol):
Symbol.__init__(self, aliases, other_symbol.value)
self.other_symbol = other_symbol
- def res_syms(self) -> List['Symbol']:
+ def res_syms(self) -> list['Symbol']:
return self.other_symbol.res_syms()
- def get_as_dealiased_symbols(self) -> List[Symbol]:
+ def get_as_dealiased_symbols(self) -> list[Symbol]:
return self.other_symbol.get_as_dealiased_symbols()
@@ -210,17 +227,30 @@ class Scope(Scopeable):
def __init__(self, aliases: Optional[Aliases]):
Scopeable.__init__(self, aliases)
# collection of known mappings that can be looked up quickly
- self.symbols: Dict[str, List[Symbol]] = defaultdict(list)
- self.imported_scopes: List[Scope] = []
+ self.symbols: Dict[str, list[Symbol]] = defaultdict(list)
+
+ # list of imported scopes, this is done lazily instead of precomputing a list of symbols and adding it to a
+ # local cache as searches in the symbol tree can be complex and the structure may change after an import is done
+ # By delaying it, we don't have to worry about when import_symbols_from_scope is called
+ self.imported_scopes: list[Scope] = []
def is_defined(self, name: str) -> bool:
- # check if the name exists in the table and it contains something
+ """
+ Check if the name exists in the current scopes local table, i.e. whether it was declared in the current scope
+ """
+ # TODO: rename function to is_declared
return name in self.symbols and bool(self.symbols[name])
def get_direct_children(self) -> Collection[Symbol]:
+ """
+ Get all children declared directly in this scope
+ """
return set([item for sublist in self.symbols.values() for item in sublist])
def get_all_children(self, collect_predicate, explore_branch_predicate):
+ """
+ Tree explorer for all DECLARED children and grandchildren, i.e. doesn't look at imports
+ """
for direct_child in self.get_direct_children():
if collect_predicate(direct_child):
yield direct_child
@@ -228,7 +258,10 @@ def get_all_children(self, collect_predicate, explore_branch_predicate):
if isinstance(direct_child, Scope) and explore_branch_predicate(direct_child):
yield from direct_child.get_all_children(collect_predicate, explore_branch_predicate)
- def get_all_functions(self):
+ def get_all_functions(self) -> list['ModFunErrEvtScope']:
+ """
+ Gets all DECLARED functions in the current scope/descendant scopes
+ """
# common case for some operators: get child functions
collect = lambda s: isinstance(s.value, solnodes.FunctionDefinition)
# don't explore into UsingDirectives, don't want to collect UsingFunctionSymbols for the caller
@@ -236,31 +269,56 @@ def get_all_functions(self):
return self.get_all_children(collect, explore)
def import_symbols_from_scope(self, other_scope: 'Scope'):
+ """
+ Links the symbols in another scope to the current scope, i.e. makes the imported symbols visible in the current
+ scope
+
+ :param other_scope: The scope whose symbols should be imported
+ """
self.imported_scopes.append(other_scope)
def add_global_symbol(self, symbol: Symbol):
+ """
+ Helper function to add a symbol to the global scope(RootScope)
+ """
root_scope = self.find_first_ancestor_of(RootScope)
root_scope.add(symbol)
def add(self, symbol: Symbol):
+ """
+ Adds a symbol to the current scope and set its parent scope to this scope
+ """
symbol.set_parent_scope(self)
for name in symbol.aliases:
self.symbols[name].append(symbol)
- def find_current_level(self, name: str, predicate=None, visited_scopes: Set = None) -> Optional[List[Symbol]]:
+ def find_current_level(self, name: str, predicate=None, visited_scopes: Set['Scope'] = None) -> list[Symbol]:
+ """
+ Finds symbols in this scope or any imported scopes at the current "level". A level is roughly the scopes that
+ are visible by an expression in the current scope.
+ """
+
+ # to avoid infinite recursion with imports
if visited_scopes is not None:
if self in visited_scopes:
return []
visited_scopes.add(self)
+ # first check the local table for the symbol
found_symbols = test_predicate(self.find_local(name), predicate)
+ # then check the imported scopes
if not found_symbols:
found_symbols = self.find_imported(name, predicate, visited_scopes)
return found_symbols
- def find_imported(self, name: str, predicate=None, visited_scopes: Set = None) -> Optional[List[Symbol]]:
+ def find_imported(self, name: str, predicate=None, visited_scopes: Set = None) -> list[Symbol]:
+ """
+ Finds the given name in all the imported scopes that are linked to the current scope. This can match many
+ valid symbols so it is up to the caller to choose the right one, however, the results are deduplicated by
+ checking that two symbols dealias to the same symbol.
+ """
found_already = set()
results = []
for scope in self.imported_scopes:
@@ -268,16 +326,19 @@ def find_imported(self, name: str, predicate=None, visited_scopes: Set = None) -
_add_to_results(syms, results, found_already)
return results
- def find_local(self, name: str) -> Optional[List[Symbol]]:
- """Finds a mapped symbol in this scope only"""
+ def find_local(self, name: str) -> list[Symbol]:
+ """Finds symbols in this scope's symbol table only"""
if name in self.symbols:
return list(self.symbols[name])
return []
- def find_from_parent(self, name: str, predicate=None) -> List[Symbol]:
+ def find_from_parent(self, name: str, predicate=None) -> list[Symbol]:
return self.parent_scope.find(name, predicate=predicate) if self.parent_scope else []
- def find_multi_part_symbol(self, name, find_base_symbol: bool = False, predicate=None):
+ def find_multi_part_symbol(self, name: str, find_base_symbol: bool = False, predicate=None):
+ """
+ Finds a potentially multi-part/qualified symbol (e.g. a.b.c)
+ """
if '.' in name:
parts = name.split('.')
s = self
@@ -287,7 +348,19 @@ def find_multi_part_symbol(self, name, find_base_symbol: bool = False, predicate
else:
return self.find_single(name, find_base_symbol=find_base_symbol, predicate=predicate)
- def find(self, name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> Optional[List[Symbol]]:
+ def find(self, name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> list[Symbol]:
+ """
+ Entry point for the symbol finder. Finds the given name in this scope and any imported scopes
+
+ Parameters:
+ name (str): The name to search for.
+ find_base_symbol (bool): Whether to find base symbols.
+ predicate (function): A function to filter symbols.
+ dealias (bool): Whether to dealias symbols.
+
+ Returns:
+ list[Symbol]: A list of symbols that match the search criteria.
+ """
visited_scopes = set()
# check this scope first
found_symbols = self.find_current_level(name, predicate, visited_scopes)
@@ -311,7 +384,17 @@ def find_single(self, name: str, find_base_symbol: bool = False, default=None, p
results = self.find(name, find_base_symbol=find_base_symbol, predicate=predicate)
return self._check_single_symbol(name, results, default)
- def find_user_type_scope(self, name, find_base_symbol: bool = False, default=None, predicate=None) -> 'Scope' | List['Scope']:
+ def find_user_type_scope(self, name, find_base_symbol: bool = False, default=None, predicate=None) -> Union['Scope', list['Scope']]:
+ """
+ Finds the scope of a user-defined type based on the given name.
+ :param name: The name of the type
+ :param find_base_symbol: Whether to find the base symbol or whether using scopes are acceptable results
+ :param default: The default value to return if no matches are found
+ :param predicate: Optional function to filter during the search
+
+ :return: A single scope if find_base_symbol is True, or a list of scopes if find_base_symbol is False
+ """
+
if not default and not find_base_symbol:
default = []
# find_base_symbol causes this function to return the single base scope(i.e. a Contract/Lib/etc Scope)
@@ -320,28 +403,37 @@ def find_user_type_scope(self, name, find_base_symbol: bool = False, default=Non
# represent this name
if '.' in name:
+ # if it's qualified, recurse to find any possible base. I don't think it matters which we find if there are
+ # multiple(e.g. a LibraryScope and a ProxyScope of that LibraryScope) but this might need to be tested
qualifier, search_str = name.rsplit('.', 1)
+ # find_base_symbol for the reason above
scope_to_search_in = self.find_user_type_scope(qualifier, find_base_symbol=True, predicate=predicate)
else:
scope_to_search_in, search_str = self, name
+ # base predicates: only care about top level units for user types (e.g. Contract, Library, Enum etc) and don't
+ # include any using scopes inherited from base contracts(as they aren't inheritable in Solidity)
pred_fs = [
predicate_ignore_inherited_usings(scope_to_search_in),
predicate_accept_top_levels
]
+ # add our own predicate if we have one
if predicate:
pred_fs.append(predicate)
+ # helper to combine our predicates, returns a predicate
def total_pred(preds):
def accept(symbol):
return all([p(symbol) for p in preds])
return accept
+ # predicate to only return using scopes
def only_using_scopes(symbol):
return isinstance(symbol, ProxyScope) and isinstance(symbol.created_by, UsingDirectiveScope)
def do_search(using_mode):
+ # search function depending on whether we're looking for using scopes or not
if using_mode:
search_pred = total_pred(pred_fs + [only_using_scopes])
else:
@@ -349,6 +441,7 @@ def do_search(using_mode):
results = scope_to_search_in.find(search_str, predicate=search_pred, dealias=False)
if not find_base_symbol:
+ # if we don't have to determine which one is the base symbol, return them all
return results
# the only proxy scope allowed in the results is the one created in the current contract
@@ -359,7 +452,9 @@ def do_search(using_mode):
return scope_to_search_in._check_single_symbol(search_str, results, default)
# This double search, first to find using scopes only and then to find non using scopes is to fix the case in
- # testcases/using_directives/DefinedInSameScope.sol
+ # testcases/using_directives/DefinedInSameScope.sol, i.e. prioritise using scopes over non using scopes.
+ # We don't have to do this for find_type for primitive/function/etc types because these types can't be declared
+ # so there won't be a conflict between a base scope(i.e. one that declares the type) and a using scope
result = do_search(True)
if not result:
@@ -370,17 +465,39 @@ def do_search(using_mode):
return result.res_syms_single() if find_base_symbol else result
- def find_type(self, ttype, predicate=None, as_single=False) -> 'Scope':
+ # These don't work because Pycharm is broken: See PY-42137
+ # @overload
+ # def find_type(self, ttype, predicate=None, as_single: Literal[True] = True) -> 'Scope':
+ # ...
+ #
+ # @overload
+ # def find_type(self, ttype, predicate=None, as_single: Literal[False] = False) -> list['Scope']:
+ # ...
+
+ def find_type(self, ttype, predicate=None, as_single=False) -> Optional['Scope'] | list['Scope']:
+ """
+ Finds the scope for the given type in the current scope. The type scope might be different to the scope of the
+ type where the type was defined because of using statements.
+ A scope is created if one isn't visible in the current scope.
+
+ :param ttype: The type to search for, CANNOT be a user type, use `find_user_type_scope` for that case
+ :param predicate: Optional function to filter during the search
+ :param as_single: Whether to return a single scope or a list of scopes
+
+ :return: The scope if as_single is True or a list of scopes if as_single is False
+ """
+
+ # this key looks like so it can't ever clash with any user defined symbols
key = type_key(ttype)
if as_single:
possible_scope = self.find_single(key, predicate=predicate)
if possible_scope:
- return possible_scope
+ return cast(Scope, possible_scope)
else:
possible_scopes = self.find(key, predicate=predicate)
if possible_scopes:
- return possible_scopes
+ return cast(list[Scope], possible_scopes)
if ttype.is_array():
# Arrays are also kind of meta types but the key is formed as a normal type key instead of a metatype
@@ -391,7 +508,7 @@ def find_type(self, ttype, predicate=None, as_single=False) -> 'Scope':
# We add them all regardless of the storage type and will let code later on handle the rules for
# allowing calls to arrays with the wrong storage location.
- values = [('length', solnodes.IntType(False, 256))]
+ values = [('length', soltypes.IntType(False, 256))]
# These are not available for String (which is a subclass of Array)
methods = [
# TODO: should these be copied?
@@ -408,14 +525,14 @@ def find_type(self, ttype, predicate=None, as_single=False) -> 'Scope':
methods = []
if ttype.is_function():
# Function selector, specific to the function type itself
- fields.append(('selector', solnodes.FixedLengthArrayType(solnodes.ByteType(), 4)))
+ fields.append(('selector', soltypes.FixedLengthArrayType(soltypes.ByteType(), 4)))
# before solidity 0.7 instead of f{gas: x, value: y)(args), f.gas(x).value(y)(args) was the way
# options were passed
# To simulate this, we stub value and gas as functions that have the function type itself as the
# return type
methods = [
- ('value', [solnodes.IntType(False, 256)], [ttype]),
- ('gas', [solnodes.IntType(False, 256)], [ttype]),
+ ('value', [soltypes.IntType(False, 256)], [ttype]),
+ ('gas', [soltypes.IntType(False, 256)], [ttype]),
]
scope = create_builtin_scope(key, ttype, values=fields, functions=methods)
self.add_global_symbol(scope)
@@ -433,7 +550,7 @@ def find_metatype(self, ttype, is_interface, is_enum) -> 'Scope':
# Create a meta type entry in the symbol table
# Fields from https://docs.soliditylang.org/en/latest/units-and-global-variables.html#type-information
members = [
- ('name', solnodes.StringType()), ('creationCode', bytes()),
+ ('name', soltypes.StringType()), ('creationCode', bytes()),
('runtimeCode', bytes())
]
@@ -446,7 +563,7 @@ def find_metatype(self, ttype, is_interface, is_enum) -> 'Scope':
# Interfaces have interfaceId (bytes4)
# if is_interface:
- members.append(('interfaceId', solnodes.FixedLengthArrayType(solnodes.ByteType(), 4)))
+ members.append(('interfaceId', soltypes.FixedLengthArrayType(soltypes.ByteType(), 4)))
# Create the scope based on the above selected members
self.add_global_symbol(scope := create_builtin_scope(key, ttype, values=members))
@@ -459,6 +576,7 @@ def find_metatype(self, ttype, is_interface, is_enum) -> 'Scope':
assert False, 'Can\'t base metatype scope on another scope'
def str__symbols(self, level=0):
+ """ Returns a string representation of all symbols in this scope and its children with indentation """
indent = ' ' * level
indent1 = ' ' + indent
@@ -496,14 +614,14 @@ def __init__(self, name: str, value=None):
class BuiltinFunction(Symbol):
- def __init__(self, name: str, input_types: List[solnodes.Type], output_types: List[solnodes.Type]):
+ def __init__(self, name: str, input_types: list[soltypes.Type] | None, output_types: list[soltypes.Type] | None):
ScopeAndSymbol.__init__(self, name, None)
self.input_types = input_types
self.output_types = output_types
class BuiltinValue(Symbol):
- def __init__(self, name: str, ttype: solnodes.Type):
+ def __init__(self, name: str, ttype: soltypes.Type):
ScopeAndSymbol.__init__(self, name, None)
self.ttype = ttype
@@ -537,20 +655,20 @@ def __init__(self, parser_version: version_util.Version):
self.compiler_version = None
msg_object = BuiltinObject('msg')
- msg_object.add(BuiltinValue('value', solnodes.IntType(False, 256)))
+ msg_object.add(BuiltinValue('value', soltypes.IntType(False, 256)))
# The function gasleft was previously known as msg.gas, which was deprecated in version 0.4.21 and removed in
# version 0.5.0
- msg_object.add(BuiltinValue('gas', solnodes.IntType(False, 256)))
+ msg_object.add(BuiltinValue('gas', soltypes.IntType(False, 256)))
# Sender is actually not payable as per 0.8 breaking changes, but if we make it not payable it breaks
# some pre 0.8 contracts, need a way to version symtab behaviour in AST2
if parser_version:
- sender_type = solnodes.AddressType(parser_version.minor < 8)
+ sender_type = soltypes.AddressType(parser_version.minor < 8)
else:
# default to not payable as the majority of stuff now is >0.8
- sender_type = solnodes.AddressType(False)
+ sender_type = soltypes.AddressType(False)
msg_object.add(BuiltinValue('sender', sender_type))
msg_object.add(BuiltinValue('data', bytes()))
- msg_object.add(BuiltinValue('sig', solnodes.FixedLengthArrayType(solnodes.ByteType(), 4)))
+ msg_object.add(BuiltinValue('sig', soltypes.FixedLengthArrayType(soltypes.ByteType(), 4)))
self.add(msg_object)
@@ -576,7 +694,7 @@ def __init__(self, parser_version: version_util.Version):
block_object = BuiltinObject('block')
block_object.add(BuiltinValue('basefee', uint()))
block_object.add(BuiltinValue('chainid', uint()))
- block_object.add(BuiltinValue('coinbase', solnodes.AddressType(True)))
+ block_object.add(BuiltinValue('coinbase', soltypes.AddressType(True)))
block_object.add(BuiltinValue('difficulty', uint()))
block_object.add(BuiltinValue('gaslimit', uint()))
block_object.add(BuiltinValue('number', uint()))
@@ -587,7 +705,7 @@ def __init__(self, parser_version: version_util.Version):
tx_object = BuiltinObject('tx')
tx_object.add(BuiltinValue('gasprice', uint()))
- tx_object.add(BuiltinValue('origin', solnodes.AddressType(False)))
+ tx_object.add(BuiltinValue('origin', soltypes.AddressType(False)))
self.add(tx_object)
bytes_object = BuiltinObject('bytes')
@@ -595,13 +713,13 @@ def __init__(self, parser_version: version_util.Version):
self.add(bytes_object)
string_object = BuiltinObject('string')
- string_object.add(BuiltinFunction('concat', None, [solnodes.StringType()]))
+ string_object.add(BuiltinFunction('concat', None, [soltypes.StringType()]))
self.add(string_object)
# https://docs.soliditylang.org/en/latest/units-and-global-variables.html#members-of-address-types
def address_object(payable):
# key is or
- t = solnodes.AddressType(payable)
+ t = soltypes.AddressType(payable)
scope = BuiltinObject(type_key(t), t)
scope.add(BuiltinValue('balance', uint()))
scope.add(BuiltinValue('code', bytes()))
@@ -611,13 +729,13 @@ def address_object(payable):
# enforced in the compiler...
# if payable:
scope.add(BuiltinFunction('transfer', [uint()], []))
- scope.add(BuiltinFunction('send', [uint()], [solnodes.BoolType()]))
+ scope.add(BuiltinFunction('send', [uint()], [soltypes.BoolType()]))
- scope.add(BuiltinFunction('call', None, [solnodes.BoolType(), bytes()]))
+ scope.add(BuiltinFunction('call', None, [soltypes.BoolType(), bytes()]))
# scope.add(BuiltinFunction('call', [bytes()], [solnodes.BoolType(), bytes()]))
# scope.add(BuiltinFunction('call', [], [solnodes.BoolType(), bytes()]))
- scope.add(BuiltinFunction('delegatecall', [bytes()], [solnodes.BoolType(), bytes()]))
- scope.add(BuiltinFunction('staticcall', [bytes()], [solnodes.BoolType(), bytes()]))
+ scope.add(BuiltinFunction('delegatecall', [bytes()], [soltypes.BoolType(), bytes()]))
+ scope.add(BuiltinFunction('staticcall', [bytes()], [soltypes.BoolType(), bytes()]))
return scope
@@ -634,22 +752,22 @@ def address_object(payable):
self.add(BuiltinFunction('mulmod', [uint(), uint(), uint()], [uint()]))
self.add(BuiltinFunction('ecrecover', [bytes32(), uint(8), bytes32(), bytes32()], [
- solnodes.AddressType(False)]))
+ soltypes.AddressType(False)]))
self.add(BuiltinFunction('gasleft', [], [uint()]))
self.add(BuiltinFunction('blobhash', [uint()], [bytes32()]))
self.add(BuiltinFunction('blockhash', [uint()], [bytes32()]))
- self.add(BuiltinFunction('require', [solnodes.BoolType(), solnodes.StringType()], []))
- self.add(BuiltinFunction('require', [solnodes.BoolType()], []))
+ self.add(BuiltinFunction('require', [soltypes.BoolType(), soltypes.StringType()], []))
+ self.add(BuiltinFunction('require', [soltypes.BoolType()], []))
- self.add(BuiltinFunction('assert', [solnodes.BoolType()], []))
+ self.add(BuiltinFunction('assert', [soltypes.BoolType()], []))
- self.add(BuiltinFunction('revert', [solnodes.StringType()], []))
+ self.add(BuiltinFunction('revert', [soltypes.StringType()], []))
self.add(BuiltinFunction('revert', [], []))
- self.add(BuiltinFunction('selfdestruct', [solnodes.AddressType(is_payable=False)], []))
+ self.add(BuiltinFunction('selfdestruct', [soltypes.AddressType(is_payable=False)], []))
class FileScope(ScopeAndSymbol):
@@ -657,7 +775,7 @@ class FileScope(ScopeAndSymbol):
def alias(source_unit_name: str):
return f''
- def __init__(self, builder: 'Builder2', vfs: VirtualFileSystem, source_unit_name: str, ast1_units: List[solnodes.SourceUnit]):
+ def __init__(self, builder: 'Builder2', vfs: VirtualFileSystem, source_unit_name: str, ast1_units: list[solnodes.SourceUnit]):
ScopeAndSymbol.__init__(self, self.alias(source_unit_name), ast1_units)
self.builder = builder
self.vfs = vfs
@@ -682,7 +800,7 @@ class ContractOrInterfaceScope(ScopeAndSymbol):
def __init__(self, ast_node: Union[solnodes.ContractDefinition, solnodes.InterfaceDefinition]):
ScopeAndSymbol.__init__(self, ast_node.name.text, ast_node)
- def find_current_level(self, name: str, predicate=None, visited_scopes: Set = None, check_hierarchy=True) -> Optional[List[Symbol]]:
+ def find_current_level(self, name: str, predicate=None, visited_scopes: Set = None, check_hierarchy=True) -> Optional[list[Symbol]]:
found_already = set()
results = []
@@ -701,9 +819,9 @@ def find_in_contract_hierarchy(self, name: str, predicate, visited_scopes):
ss.extend(syms)
return ss
- def get_supers(self) -> List['ContractOrInterfaceScope']:
+ def get_supers(self) -> list['ContractOrInterfaceScope']:
klass_file_scope: FileScope = self.parent_scope
- superklasses: List[ContractOrInterfaceScope] = []
+ superklasses: list[ContractOrInterfaceScope] = []
for inherit_specifier in self.value.inherits:
# inherit specifier => name type => name ident => text str
name = inherit_specifier.name.name.text
@@ -746,7 +864,7 @@ class ImportSymbol(ScopeAndSymbol):
def __init__(self, aliases: Optional[Aliases], ast_node: solnodes.ImportDirective):
ScopeAndSymbol.__init__(self, aliases, ast_node)
- def get_as_dealiased_symbols(self) -> List['Symbol']:
+ def get_as_dealiased_symbols(self) -> list['Symbol']:
return [dea_sym for i_s in self._get_imported_symbols() for dea_sym in i_s.get_as_dealiased_symbols()]
def get_imported_scope(self) -> Optional[FileScope]:
@@ -754,25 +872,25 @@ def get_imported_scope(self) -> Optional[FileScope]:
import_path = self.value.path
return source_unit.get_imported_source_unit(import_path)
- def _get_imported_symbols(self) -> List[Symbol]:
+ def _get_imported_symbols(self) -> list[Symbol]:
pass
- def res_syms(self) -> List['Symbol']:
+ def res_syms(self) -> list['Symbol']:
return [res_sym for i_s in self._get_imported_symbols() for res_sym in i_s.res_syms()]
def get_direct_children(self) -> Collection[Symbol]:
return [direct_child for i_s in self._get_imported_symbols() for direct_child in i_s.get_direct_children()]
- def find(self, name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> Optional[List[Symbol]]:
+ def find(self, name: str, find_base_symbol: bool = False, predicate=None, dealias: bool = True) -> Optional[list[Symbol]]:
return [f_s for i_s in self._get_imported_symbols() for f_s in i_s.find(name, find_base_symbol, predicate, dealias)]
- def find_type(self, ttype) -> Scope:
- raise NotImplemented
+ # def find_type(self, ttype, predicate=None, as_single=False) -> Scope:
+ # raise NotImplemented
def find_metatype(self, ttype, is_interface, is_enum) -> Scope:
raise NotImplemented
- def find_local(self, name: str) -> Optional[List[Symbol]]:
+ def find_local(self, name: str) -> Optional[list[Symbol]]:
return [f_s for i_s in self._get_imported_symbols() for f_s in i_s.find_local(name)]
def find_first_ancestor(self, predicate, get_parent=None):
@@ -781,10 +899,10 @@ def find_first_ancestor(self, predicate, get_parent=None):
def find_first_ancestor_of(self, ttype: Union[Type, Tuple[Type]]):
return NotImplemented
- def find_imported(self, name: str, predicate=None, visited_scopes: Set = None) -> Optional[List[Symbol]]:
+ def find_imported(self, name: str, predicate=None, visited_scopes: Set = None) -> Optional[list[Symbol]]:
return [f_s for i_s in self._get_imported_symbols() for f_s in i_s.find_imported(name, predicate, visited_scopes)]
- def find_current_level(self, name: str, predicate=None, visited_scopes: Set = None) -> Optional[List[Symbol]]:
+ def find_current_level(self, name: str, predicate=None, visited_scopes: Set = None) -> Optional[list[Symbol]]:
return [f_s for i_s in self._get_imported_symbols() for f_s in i_s.find_current_level(name, predicate, visited_scopes)]
def find_single(self, name: str, find_base_symbol: bool = False, default=None, predicate=None) -> Optional[Symbol]:
@@ -792,7 +910,7 @@ def find_single(self, name: str, find_base_symbol: bool = False, default=None, p
results = [f_s for i_s in self._get_imported_symbols() for f_s in i_s.find_single(name, find_base_symbol, [], predicate)]
return self._check_single_symbol(name, results, default)
- def find_from_parent(self, name: str, predicate=None) -> List[Symbol]:
+ def find_from_parent(self, name: str, predicate=None) -> list[Symbol]:
return [f_s for i_s in self._get_imported_symbols() for f_s in i_s.find_from_parent(name, predicate)]
@@ -805,7 +923,7 @@ def __init__(self, ast_node: solnodes.SymbolImportDirective, alias_index):
self.alias_index = alias_index
ImportSymbol.__init__(self, ast_node.aliases[alias_index].alias.text, ast_node)
- def _get_imported_symbols(self) -> List['Symbol']:
+ def _get_imported_symbols(self) -> list['Symbol']:
alias: solnodes.SymbolAlias = self.value.aliases[self.alias_index]
symbol_name = alias.symbol.text
imported_scope = self.get_imported_scope()
@@ -818,7 +936,7 @@ class UnitImportSymbol(ImportSymbol):
def __init__(self, ast_node: solnodes.UnitImportDirective):
ImportSymbol.__init__(self, ast_node.alias.text, ast_node)
- def _get_imported_symbols(self) -> List['Symbol']:
+ def _get_imported_symbols(self) -> list['Symbol']:
return self.get_imported_scope().res_syms()
@@ -828,8 +946,9 @@ def __init__(self, name: str, base_scope: ScopeAndSymbol):
if base_scope:
self.import_symbols_from_scope(base_scope)
self.base_scope = base_scope
+ self.created_by = None
- def res_syms(self) -> List['Symbol']:
+ def res_syms(self) -> list['Symbol']:
if self.base_scope:
return self.base_scope.res_syms()
else:
@@ -842,25 +961,44 @@ def __init__(self, node: solnodes.UsingDirective):
class UsingFunctionSymbol(Symbol):
- def __init__(self, target: ModFunErrEvtScope, override_type: solnodes.Type):
+ """
+ Symbol for a function that was added to the current scope by a Solidity using statement. Solidity docs state that
+ all functions, even those that don't match the type specifier in the using statement have to be added to the scope
+ the using statement is declared in. This symbol type is required instead of the usual ModFunErrEvtSymbol as we need
+ to be able to associate the bound type from the using statement and the first parameter type of the "value" of this
+ symbol(i.e. the FunctionDefinition) may or may not be the same as the specified one.
+ """
+ def __init__(self, target: ModFunErrEvtScope, override_type: soltypes.Type):
+ """
+ :param target: Symbol that represents the real definition of the function that this symbol represents
+ :param override_type: The type declared in the using statement
+ """
+
+ # the value of this symbol is still the real function definition and the aliases are also the same so that
+ # lookups in the symtab can find it
assert isinstance(target.value, solnodes.FunctionDefinition)
Symbol.__init__(self, target.aliases, target.value)
self.target = target
self.override_type = override_type
- def res_syms(self) -> List['Symbol']:
+ def res_syms(self) -> list['Symbol']:
return self.target.res_syms()
class UsingOperatorSymbol(Symbol):
- def __init__(self, target: ModFunErrEvtScope, override_type: solnodes.Type, operator: Union[solnodes.UnaryOpCode, solnodes.BinaryOpCode]):
+ """
+ Similar to UsingFunctionSymbol except for operator overloads
+ """
+ def __init__(self, target: ModFunErrEvtScope, override_type: soltypes.Type, operator: Union[solnodes.UnaryOpCode, solnodes.BinaryOpCode]):
assert isinstance(target.value, solnodes.FunctionDefinition)
+ # the alias of the symbol is the __str__ function of the operator, this should just be the same as the Solidity
+ # operator text
Symbol.__init__(self, f'{str(operator.value)}', target.value)
self.target = target
self.override_type = override_type
self.operator = operator
- def res_syms(self) -> List['Symbol']:
+ def res_syms(self) -> list['Symbol']:
return self.target.res_syms()
@@ -897,7 +1035,7 @@ def process_or_find_from_base_dir(self, relative_source_unit_name: str):
return fs
return self.process_file(source_unit_name)
- def process_file(self, source_unit_name: str, source_units: List[solnodes.SourceUnit] = None):
+ def process_file(self, source_unit_name: str, source_units: list[solnodes.SourceUnit] = None):
if source_units is None:
source = self.vfs.lookup_import_path(source_unit_name, '')
source_units = source.ast
@@ -944,7 +1082,7 @@ def add_node_dfs(self, parent_scope, node, context: Context, build_skeletons, vi
assert parent_scope is not None, 'No parent scope'
if build_skeletons:
- assert not hasattr(node, 'scope')
+ assert not node.scope
# the nodes scope is the scope it was created in always
node.scope = parent_scope
@@ -1086,12 +1224,12 @@ def add_to_scope(self, parent: Scope, *children: Symbol):
for child in children:
parent.add(child)
- def make_scope(self, node: solnodes.Node, name=None):
+ def make_scope(self, node: nodebase.Node, name=None):
if name is None:
name = node.name.text
return ScopeAndSymbol(name, node)
- def make_symbol(self, node: solnodes.Node, sym_type=Symbol, name=None):
+ def make_symbol(self, node: nodebase.Node, sym_type=Symbol, name=None):
if name is None:
name = node.name.text
return sym_type(name, node)
@@ -1099,7 +1237,7 @@ def make_symbol(self, node: solnodes.Node, sym_type=Symbol, name=None):
def scope_name(self, base_name, node):
return f'<{base_name}>@{node.location}'
- def find_using_target_scope_and_name(self, current_scope, target_type: solnodes.Type):
+ def find_using_target_scope_and_name(self, current_scope, target_type: soltypes.Type):
# TODO: Not sure if this is possible and I don't want to handle it(yet), just want to handle Types
# for target_type
if isinstance(target_type, solnodes.Ident):
@@ -1108,18 +1246,10 @@ def find_using_target_scope_and_name(self, current_scope, target_type: solnodes.
# Need to get the symbol name/alias/key for the target type, for primitives this is easy: just encode it
# as a type key. For user reference types, it depends on how it's referenced, e.g. it could be just
# MyT or could be qualified as A.B.MyT where B is in the scope of A and MyT is in the scope of B (etc)
- if isinstance(target_type, solnodes.UserType):
+ if isinstance(target_type, soltypes.UserType):
raw_name = target_type.name.text
target_type_scope = current_scope.find_user_type_scope(raw_name, find_base_symbol=True)
- # NOTE: with find_user_type_scope now, this shouldn't happen
- # target_type_scope = current_scope.find_multi_part_symbol(raw_name, predicate=ACCEPT_NO_INHERITED_USINGS(current_scope))
- # if not target_type_scope:
- # # happened in a case where a contract imported a Type 'Delay' from 'Time' and used Time.Delay in the
- # # contract, but in the 'Time' library the type was referenced as 'Delay' => 'Delay' wasn't defined in
- # # the current contract but was defined in the library.
- # target_type_scope = target_type.scope.find_multi_part_symbol(raw_name, predicate=ACCEPT_NO_INHERITED_USINGS(current_scope))
-
# Resolve the name used here to the actual contract/struct/etc (symbol)
# Use the name as defined by the actual symbol itself so that we can do consistent checks against
# this type and the first parameter type later, i.e. for A.B.MyT, use MyT as the type key
@@ -1337,7 +1467,7 @@ def process_using_functions(self, node: solnodes.UsingDirective, context: Contex
self.add_to_scope(scope_to_add_to, s)
def process_using_directive(self, node: solnodes.UsingDirective, context: Context):
- if isinstance(node.override_type, solnodes.AnyType):
+ if isinstance(node.override_type, soltypes.AnyType):
if node.is_global:
raise ValueError(f'Using @{node.location} can\'t be global')
self.process_using_any_type(context, node)
@@ -1404,7 +1534,7 @@ def make_symbols_for_node(self, node, context: Context, build_skeletons: bool, v
node.owning_scope.import_symbols_from_scope(target_scope)
# also add the builtin helper methods
- udvt_type = solnodes.UserType(solnodes.Ident(node.name.text))
+ udvt_type = soltypes.UserType(solnodes.Ident(node.name.text))
# set the scope of this node: when it's looked up later, it needs a scope
udvt_type.scope = node.owning_scope
diff --git a/src/solidity_parser/ast/types.py b/src/solidity_parser/ast/types.py
new file mode 100644
index 0000000..68b537f
--- /dev/null
+++ b/src/solidity_parser/ast/types.py
@@ -0,0 +1,603 @@
+from abc import ABC, abstractmethod
+from dataclasses import field
+from solidity_parser.ast.nodebase import NodeDataclass, Node
+
+
+@NodeDataclass
+class Type(Node, ABC):
+ scope: 'Scope' = field(default=None, init=False, repr=False, compare=False, hash=False)
+ """
+ Shim for symbol table scoping. The scope field is also defined in solnodes1 Node but since this base class is
+ defined in this file, it must be defined here as well
+ """
+
+ @staticmethod
+ def are_matching_types(target_param_types, actual_param_types):
+ if not len(target_param_types) == len(actual_param_types):
+ return False
+
+ # check if the actual args types are passable to the target types
+ return all([a.can_implicitly_cast_from(b) for a,b in zip(target_param_types, actual_param_types)])
+
+ def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
+ # Check whether actual_type can be converted to this type implicitly
+ # Default case is if the types are equal
+ return self == actual_type
+
+ def is_builtin(self) -> bool:
+ """ Check if the type is a Solidity builtin type, e.g. primitives, message object, abi object, etc """
+ return False
+
+ def is_array(self) -> bool:
+ return False
+
+ def is_byte_array(self) -> bool:
+ """ Check if the type is any type of byte array, e.g. bytes, bytes1, bytes32 """
+ return (isinstance(self, ArrayType) and isinstance(self.base_type, ByteType)) or isinstance(self, BytesType)
+
+ def is_byte_array_underlying(self) -> bool:
+ """ Check if this type is logically an array of bytes, e.g. bytes, bytes1, bytes32 and string """
+ return self.is_byte_array() or self.is_string()
+
+ def is_string(self) -> bool:
+ return False
+
+ def is_function(self) -> bool:
+ return False
+
+ def is_int(self) -> bool:
+ return False
+
+ def is_bool(self) -> bool:
+ return False
+
+ def is_user_type(self) -> bool:
+ """ Check if the type is a user defined type, e.g. struct, enum, contract, etc """
+ return False
+
+ def is_address(self) -> bool:
+ return False
+
+ def is_mapping(self) -> bool:
+ return False
+
+ def is_byte(self) -> bool:
+ """ Check if the type is a single "byte" """
+ return False
+
+ def is_tuple(self) -> bool:
+ """ Check if the type is a tuple. These are synthetic types in Solidity but can be used in ASTs """
+ return False
+
+ def is_literal_type(self) -> bool:
+ """ Check if the type is a literal type, i.e. an inferred type from a constant number or string expression.
+ These are not real types in Solidity but are used in solc to aid type inference and optimization rules
+ """
+ return False
+
+ def is_float(self) -> bool:
+ """ Check whether this type is a compile time float"""
+ return False
+
+ def is_void(self) -> bool:
+ """ Check if the type represents a void return type. This isn't part of Solidity directly but is represented
+ when a function doesn't define any return types
+ """
+ return False
+
+ def type_key(self):
+ """ Returns a unique key for the type that can be used to cache types in the symbol table """
+ return self.code_str()
+
+ @abstractmethod
+ def __str__(self):
+ pass
+
+ def code_str(self):
+ """ Returns the string representation of the type in Solidity syntax"""
+ pass
+
+
+@NodeDataclass
+class FloatType(Type):
+ """
+ This is not a real type in valid Solidity code but the Solidity compiler allows compile time expression evaluation
+ of floats
+ """
+
+ value: float
+ """ Since the value is always known at compile time, we have it here """
+
+ def is_float(self) -> bool:
+ return True
+
+ def __str__(self):
+ return 'float'
+
+ def code_str(self):
+ return str(self)
+
+ def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
+ if super().can_implicitly_cast_from(actual_type):
+ return True
+ return actual_type.is_float()
+
+
+@NodeDataclass
+class VoidType(Type):
+ def is_void(self) -> bool:
+ return True
+
+ def is_builtin(self) -> bool:
+ return True
+
+ def code_str(self):
+ return str(self)
+
+ def __str__(self):
+ return ''
+
+
+@NodeDataclass
+class ArrayType(Type):
+ """ Single dimension array type with no size attributes"""
+ base_type: Type
+
+ def __str__(self): return f"{self.base_type}[]"
+
+ def code_str(self): return f'{self.base_type.code_str()}[]'
+
+ def is_builtin(self) -> bool:
+ # e.g. byte[] is builtin, string[] is builtin, MyContract[] is not
+ return self.base_type.is_builtin()
+
+ def can_implicitly_cast_from(self, actual_type: Type) -> bool:
+ if super().can_implicitly_cast_from(actual_type):
+ return True
+ if not self.has_size() and actual_type.is_array() and actual_type.has_size():
+ # i.e. FixedLengthArrayType/VariableLengthArrayType can cast to the base ArrayType (but not each other)
+ # e.g. byte[4] casts to byte[] but not the other way around
+ return self.base_type.can_implicitly_cast_from(actual_type.base_type)
+ if self.base_type.is_byte() and not self.has_size() and actual_type.is_literal_type():
+ if self.is_string() == actual_type.is_string():
+ return True
+ if self.is_int() == actual_type.is_int():
+ return True
+
+ return False
+
+ def has_size(self) -> bool:
+ return hasattr(self, 'size')
+
+ def is_fixed_size(self) -> bool:
+ return False
+
+ def is_array(self) -> bool:
+ return True
+
+
+@NodeDataclass
+class FixedLengthArrayType(ArrayType):
+ """ Array type with a known length that is determined at compile time """
+ size: int
+
+ def __str__(self): return f"{self.base_type}[{self.size}]"
+
+ def is_fixed_size(self) -> bool:
+ return True
+
+ def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
+ if super().can_implicitly_cast_from(actual_type):
+ return True
+ if not self.is_string() and self.base_type.is_byte() and actual_type.is_int() and actual_type.is_literal_type():
+ # Decimal number literals cannot be implicitly converted to fixed-size byte arrays. Hexadecimal number literals
+ # can be, but only if the number of hex digits exactly fits the size of the bytes type. As an exception both
+ # decimal and hexadecimal literals which have a value of zero can be converted to any fixed-size bytes type:
+ return self.size >= (actual_type.size / 8)
+ if self.base_type.is_byte() and actual_type.is_string() and actual_type.is_literal_type():
+ # e.g. bytes32 samevar = "stringliteral"
+ return self.size >= actual_type.real_size
+
+ return False
+
+ def code_str(self):
+ return f'{self.base_type.code_str()}[{str(self.size)}]'
+
+
+@NodeDataclass
+class VariableLengthArrayType(ArrayType):
+ """ Array type with a length that is determined at runtime"""
+ size: 'Expr'
+
+ def __str__(self): return f"{self.base_type}[{self.size}]"
+
+ def code_str(self):
+ return f'{self.base_type.code_str()}[{self.size.code_str()}]'
+
+
+@NodeDataclass
+class AddressType(Type):
+ """ Solidity address/address payable type, functionally this is a uint160"""
+ is_payable: bool
+
+ def __str__(self): return f"address{' payable' if self.is_payable else ''}"
+
+ def can_implicitly_cast_from(self, actual_type: Type) -> bool:
+ # address_payable(actual_type) can be cast to address implicitly
+ if actual_type.is_address():
+ # Matrix:
+ # self <= actual_type = can_implicitly_cast_from
+ # AP <= AP = true
+ # AP <= A = false
+ # A <= A = true
+ # A <= AP = true
+ return not(self.is_payable and not actual_type.is_payable)
+ # contracts can get cast to address (at least in solidity 0.4.23)
+ if actual_type.is_user_type():
+ definition = actual_type.value.x
+ if definition.is_contract() or definition.is_interface():
+ return True
+ # uint160 can cast to address, I've seen this in a contract but AfterObol.sol:
+ # _mint(0x0CA5cD5790695055F0a01F73A47160C35f9d3A46, 100000000 * 10 ** decimals());
+ # but not sure how this is allowed exactly
+ # UPDATE:
+ # "Hexadecimal literals that pass the address checksum test, for example
+ # 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF are of address type. Hexadecimal literals that are between 39 and
+ # 41 digits long and do not pass the checksum test produce an error. You can prepend (for integer types) or
+ # append (for bytesNN types) zeros to remove the error."
+ # We can't do a check for hex literals (without changing some parsing code) just do it for any int
+ if not self.is_payable and actual_type.is_int() and not actual_type.is_signed and actual_type.size == 160:
+ return True
+
+ return False
+
+ def is_builtin(self) -> bool:
+ return True
+
+ def is_address(self) -> bool:
+ return True
+
+ def code_str(self):
+ return 'address' + (' payable' if self.is_payable else '')
+
+
+@NodeDataclass
+class ByteType(Type):
+ """ Single 8bit byte type """
+
+ def __str__(self): return "byte"
+
+ def is_builtin(self) -> bool:
+ return True
+
+ def is_byte(self) -> bool:
+ return True
+
+ def code_str(self):
+ return 'byte'
+
+
+def UIntType(size=256):
+ return IntType(False, size)
+
+
+def Bytes(size=None):
+ if size is not None:
+ if isinstance(size, int):
+ return FixedLengthArrayType(ByteType(), size)
+ else:
+ return VariableLengthArrayType(ByteType(), size)
+ # elif isinstance(size, Expr):
+ # return VariableLengthArrayType(ByteType(), size)
+ # else:
+ # raise NotImplementedError(f'{type(size)}')
+ else:
+ return BytesType()
+
+
+@NodeDataclass
+class BytesType(ArrayType):
+ """ bytes type only (similar but not equal to byte[]/bytes1[]) """
+ base_type: Type = field(default_factory=lambda: Bytes(1), init=False)
+
+ def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
+ # don't have anything in AST1 to mark whether the literal is a hex or dec int so we do the
+ # conversion regardless
+ # e.g. bytes public c = hex"11"; is allowed but bytes public c = 0x11; is NOT
+ if actual_type.is_literal_type() and actual_type.is_int():
+ return True
+ return super().can_implicitly_cast_from(actual_type)
+
+ def __str__(self):
+ return self.code_str()
+
+ def code_str(self):
+ return 'bytes'
+
+
+@NodeDataclass
+class IntType(Type):
+ """ Solidity native integer type of various bit length and signedness"""
+
+ is_signed: bool
+ """ Whether the type is a signed int or unsigned int """
+ size: int
+ """ Size of the type in bits """
+
+ def __str__(self): return f"{'int' if self.is_signed else 'uint'}{self.size}"
+
+ def can_implicitly_cast_from(self, actual_type: Type) -> bool:
+ if actual_type.is_int():
+ # inty(actual_type) to intx(self) if y <= x, same for uint, but not both at the same time
+ if actual_type.is_signed == self.is_signed and actual_type.size <= self.size:
+ return True
+
+ if actual_type.is_int() and actual_type.is_literal_type() and not actual_type.is_signed:
+ # e.g. calling f(1 :: uint8) where f(x: int256)
+ return actual_type.real_bit_length < self.size
+ return False
+
+ def is_builtin(self) -> bool:
+ return True
+
+ def is_int(self) -> bool:
+ return True
+
+ def code_str(self):
+ return ('u' if not self.is_signed else '') + 'int' + str(self.size)
+
+
+@NodeDataclass
+class PreciseIntType(IntType):
+ real_bit_length: int
+
+ def is_literal_type(self) -> bool:
+ return True
+
+ def __str__(self): return f"{'int' if self.is_signed else 'uint'}{self.size}({self.real_bit_length})"
+
+ def code_str(self):
+ return str(self)
+
+
+class BoolType(Type):
+ """ Solidity native boolean type"""
+
+ def __str__(self): return "bool"
+
+ def is_builtin(self) -> bool:
+ return True
+
+ def is_bool(self) -> bool:
+ return True
+
+ def code_str(self):
+ return 'bool'
+
+
+@NodeDataclass
+class StringType(ArrayType):
+ """ Solidity native string type"""
+
+ # makes this an Array[Byte] (as Solidity uses UTF8 for strings?)
+ base_type: Type = field(default_factory=lambda: Bytes(1), init=False)
+
+ def __str__(self): return "string"
+
+ def is_builtin(self) -> bool:
+ return True
+
+ def is_string(self) -> bool:
+ return True
+
+ def code_str(self):
+ return 'string'
+
+
+@NodeDataclass
+class PreciseStringType(StringType):
+ """String literal type that has a known length at compile time"""
+
+ real_size: int
+
+ def is_literal_type(self) -> bool:
+ return True
+
+ def has_size(self) -> bool:
+ # ArrayType.has_size() checks if we have a 'size' attribute, but we don't: it's called
+ # real_size(), so this shim fixes that.
+ # This allows e.g. PreciseStringType of length 1 to be implicitly castable to the base StringType
+ return True
+
+ def __str__(self): return f"string({self.real_size})"
+
+ def code_str(self):
+ return str(self)
+
+
+@NodeDataclass
+class MappingType(Type):
+ """ Type that represents a function mapping definition
+
+ For example in the mapping '(uint x => Campaign c)', src would be 'unit' and the dst would be 'Campaign',
+ src_key would be 'x' and dst_key would be 'c'
+ """
+ src: Type
+ dst: Type
+ src_name: 'Ident' = None
+ dst_name: 'Ident' = None
+
+ def __str__(self):
+ def _name(ident):
+ return (' ' + str(ident)) if ident else ''
+ return f"({self.src}{_name(self.src_name)} => {self.dst}{_name(self.dst_name)})"
+
+ def is_mapping(self) -> bool:
+ return True
+
+ def flatten(self) -> list[Type]:
+ # get a nested mapping types elements in a list
+ # e.g. (x => (y => z)) would return [x,y,z]
+ result = [self.src]
+ next_link = self.dst
+ while next_link:
+ if next_link.is_mapping():
+ result.append(next_link.src)
+ next_link = next_link.dst
+ else:
+ # base case, we hit the end of the chain
+ result.append(next_link)
+ next_link = None
+ return result
+
+ def code_str(self):
+ return str(self)
+
+
+@NodeDataclass
+class UserType(Type):
+ """
+ Type invoked using a valid Solidity reference, e.g. a class, contract, library, enum, etc name.
+ This is an "unlinked" type, e.g. it has no underlying AST node backing it and has no corresponding context other
+ than the scope it was declared in. For AST2 use solnodes2.ResolvedUserType instead.
+ """
+ name: 'Ident'
+
+ def __str__(self): return str(self.name)
+
+
+@NodeDataclass
+class BuiltinType(Type):
+ """
+ Type representing types of Solidity builtin objects, e.g. the type of the 'msg' or 'abi' objects in the expressions
+ `msg.sender` or `abi.decode(...)`
+ """
+ name: str
+
+ def __str__(self):
+ return f'Builtin<{self.name}>'
+
+ def is_builtin(self) -> bool:
+ return True
+
+ def code_str(self):
+ return self.name
+
+
+def ABIType() -> BuiltinType:
+ return BuiltinType('abi')
+
+
+@NodeDataclass
+class FunctionType(Type):
+ inputs: list[Type]
+ outputs: list[Type]
+ # "By default, function types are internal, so the internal keyword can be omitted. Note that this only applies to
+ # function types. Visibility has to be specified explicitly for functions defined in contracts, they do not have a
+ # default."
+ modifiers: list['Modifier']
+
+ def is_builtin(self) -> bool:
+ return False
+
+ def is_function(self) -> bool:
+ return True
+
+ def can_implicitly_cast_from(self, actual_type: 'Type') -> bool:
+ if super().can_implicitly_cast_from(actual_type):
+ return True
+
+ # Conversions:
+ # A function type A is implicitly convertible to a function type B if and only if their parameter types are
+ # identical, their return types are identical, their internal/external property is identical and the state
+ # mutability of A is more restrictive than the state mutability of B. In particular:
+ # pure functions can be converted to view and non-payable functions
+ # view functions can be converted to non-payable functions
+ # payable functions can be converted to non-payable functions
+ # No other conversions between function types are possible
+
+ if actual_type.is_function():
+ if len(actual_type.inputs) != len(self.inputs):
+ return False
+ return all([t1 == t2 for t1, t2 in zip(self.inputs, actual_type.inputs)])
+
+ return False
+
+ def code_str(self):
+ # function () {internal|external} [pure|view|payable] [returns ()]
+ return f'function ({", ".join(t.code_str() for t in self.inputs)}) returns ({", ".join(t.code_str() for t in self.outputs)})'
+
+ def __str__(self):
+ return self.code_str()
+
+ def type_key(self):
+ # doesn't include modifiers for now
+ input_params = ', '.join([p.type_key() for p in self.inputs])
+ output_params = ', '.join([p.type_key() for p in self.outputs])
+ return f'function ({input_params}) returns ({output_params})'
+
+
+@NodeDataclass
+class TupleType(Type):
+ """
+ Type of a tuple of elements. This is not a real Solidity type but is used to represent the type of tuple expressions
+ (e.g. desugaring) in the AST
+ """
+ ttypes: list[Type]
+
+ def is_builtin(self) -> bool:
+ return False
+
+ def is_tuple(self) -> bool:
+ return True
+
+ def code_str(self):
+ return f'({", ".join(t.code_str() for t in self.ttypes)})'
+
+ def __str__(self):
+ return f'({", ".join(str(t) for t in self.ttypes)})'
+
+
+@NodeDataclass
+class MetaTypeType(Type):
+ """
+ Metatype Solidity type, i.e. type(X). This type has a few builtin fields such as min, max, name, creationCode,
+ runtimeCode and interfaceId
+ """
+ ttype: Type
+
+ def is_builtin(self) -> bool:
+ # TODO: are these all builtin types irregardless?
+ return self.ttype.is_builtin()
+
+ def code_str(self):
+ return f'type({self.ttype.code_str()})'
+
+ def __str__(self):
+ return f'type({self.ttype})'
+
+
+@NodeDataclass
+class VarType(Type):
+ """ Type that wasn't explicitly identified in the code
+
+ This type should not be used without running a subsequent type inference pass.
+
+ An example variable declaration that would use this type symbol: 'var (, mantissa, exponent) = ... '
+ """
+
+ # I've only seen this once in ~10000 contracts where a contract used the 'var' keyword
+
+ def __str__(self): return "var"
+
+
+@NodeDataclass
+class AnyType(Type):
+ """ Type that is used only in 'using' declarations to specify that the declaration is overriding all possible types
+
+ For example in the declaration 'using SomeLibrary for *', the overriden type here is AnyType(every type
+ that is imported from SomeLibrary)
+ """
+
+ def __str__(self): return "*"
+
diff --git a/src/solidity_parser/errors.py b/src/solidity_parser/errors.py
index 6efd83e..247a6a1 100644
--- a/src/solidity_parser/errors.py
+++ b/src/solidity_parser/errors.py
@@ -1,5 +1,4 @@
import typing
-from typing import List
from collections import namedtuple
from solidity_parser.util.version_util import Version
diff --git a/test/solidity_parser/ast/helper.py b/test/solidity_parser/ast/helper.py
index 0499001..975b485 100644
--- a/test/solidity_parser/ast/helper.py
+++ b/test/solidity_parser/ast/helper.py
@@ -1,12 +1,12 @@
from snapshottest.formatters import TypeFormatter, format_list
from snapshottest.formatter import Formatter
-from solidity_parser.ast import solnodes2
+from solidity_parser.ast import nodebase
class NodeListFormatter(TypeFormatter):
def __init__(self):
- super().__init__(solnodes2.NodeList, format_list)
+ super().__init__(nodebase.NodeList, format_list)
def normalize(self, value, formatter):
return [formatter.normalize(item) for item in value]
diff --git a/test/solidity_parser/ast/snapshots/snap_test_ast2builder.py b/test/solidity_parser/ast/snapshots/snap_test_ast2builder.py
index 72bf1c6..732fd38 100644
--- a/test/solidity_parser/ast/snapshots/snap_test_ast2builder.py
+++ b/test/solidity_parser/ast/snapshots/snap_test_ast2builder.py
@@ -29,8 +29,8 @@
'Literal(value=42, unit=None) :: uint8(6)',
"BinaryOp(left=Ident(text='addressValue'), right=GetMember(obj_base=Ident(text='msg'), name=Ident(text='sender')), op=) :: address",
"GetMember(obj_base=Ident(text='msg'), name=Ident(text='sender')) :: [AddressType(is_payable=False)]",
- "BinaryOp(left=Ident(text='bytesValue'), right=CallFunction(callee=BytesType(base_type=ByteType()), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]), op=) :: bytes",
- "CallFunction(callee=BytesType(base_type=ByteType()), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]) :: bytes",
+ "BinaryOp(left=Ident(text='bytesValue'), right=CallFunction(callee=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]), op=) :: bytes",
+ "CallFunction(callee=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]) :: bytes",
"Literal(value='Hello, Solidity!', unit=None) :: string(16)",
"BinaryOp(left=Ident(text='stringValue'), right=Literal(value='Hello, World!', unit=None), op=) :: string(13)",
"Literal(value='Hello, World!', unit=None) :: string(13)",
@@ -41,10 +41,10 @@
'Literal(value=2, unit=None) :: uint8(2)',
'Literal(value=3, unit=None) :: uint8(2)',
"CallFunction(callee=GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')), modifiers=[], args=[Literal(value=4, unit=None)]) :: []",
- "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[])]",
+ "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)], modifiers=[]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[], modifiers=[])]",
'Literal(value=4, unit=None) :: uint8(3)',
"CallFunction(callee=GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')), modifiers=[], args=[Literal(value=5, unit=None)]) :: []",
- "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[])]",
+ "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)], modifiers=[]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[], modifiers=[])]",
'Literal(value=5, unit=None) :: uint8(3)',
"BinaryOp(left=Ident(text='myStructValue'), right=CallFunction(callee=Ident(text='MyStruct'), modifiers=[], args=[Literal(value=10, unit=None), Literal(value='Example', unit=None)]), op=) :: ResolvedUserType(MyStruct)",
"CallFunction(callee=Ident(text='MyStruct'), modifiers=[], args=[Literal(value=10, unit=None), Literal(value='Example', unit=None)]) :: ResolvedUserType(MyStruct)",
@@ -81,8 +81,8 @@
'Literal(value=42, unit=None) :: uint8(6)',
"BinaryOp(left=Ident(text='addressValue'), right=GetMember(obj_base=Ident(text='msg'), name=Ident(text='sender')), op=) :: address",
"GetMember(obj_base=Ident(text='msg'), name=Ident(text='sender')) :: [AddressType(is_payable=False)]",
- "BinaryOp(left=Ident(text='bytesValue'), right=CallFunction(callee=BytesType(base_type=ByteType()), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]), op=) :: bytes",
- "CallFunction(callee=BytesType(base_type=ByteType()), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]) :: bytes",
+ "BinaryOp(left=Ident(text='bytesValue'), right=CallFunction(callee=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]), op=) :: bytes",
+ "CallFunction(callee=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), modifiers=[], args=[Literal(value='Hello, Solidity!', unit=None)]) :: bytes",
"Literal(value='Hello, Solidity!', unit=None) :: string(16)",
"BinaryOp(left=Ident(text='stringValue'), right=Literal(value='Hello, World!', unit=None), op=) :: string(13)",
"Literal(value='Hello, World!', unit=None) :: string(13)",
@@ -93,10 +93,10 @@
'Literal(value=2, unit=None) :: uint8(2)',
'Literal(value=3, unit=None) :: uint8(2)',
"CallFunction(callee=GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')), modifiers=[], args=[Literal(value=4, unit=None)]) :: []",
- "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[])]",
+ "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)], modifiers=[]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[], modifiers=[])]",
'Literal(value=4, unit=None) :: uint8(3)',
"CallFunction(callee=GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')), modifiers=[], args=[Literal(value=5, unit=None)]) :: []",
- "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[])]",
+ "GetMember(obj_base=Ident(text='dynamicArray'), name=Ident(text='push')) :: [FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)], modifiers=[]), FunctionType(inputs=[IntType(is_signed=False, size=256)], outputs=[], modifiers=[])]",
'Literal(value=5, unit=None) :: uint8(3)',
"BinaryOp(left=Ident(text='myStructValue'), right=CallFunction(callee=Ident(text='MyStruct'), modifiers=[], args=[Literal(value=10, unit=None), Literal(value='Example', unit=None)]), op=) :: ResolvedUserType(MyStruct)",
"CallFunction(callee=Ident(text='MyStruct'), modifiers=[], args=[Literal(value=10, unit=None), Literal(value='Example', unit=None)]) :: ResolvedUserType(MyStruct)",
@@ -149,19 +149,19 @@
'Literal(value=False, unit=None) :: bool',
"UnaryOp(expr=Ident(text='k'), op=, is_pre=True) :: bool",
"GetMember(obj_base=CreateMetaType(base_type=UserType(name=Ident(text='AllTypesExample'))), name=Ident(text='name')) :: [StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))]",
- "CreateMetaType(base_type=UserType(name=Ident(text='AllTypesExample'))) :: MetaTypeType(ttype=ResolvedUserType(AllTypesExample))",
+ "CreateMetaType(base_type=UserType(name=Ident(text='AllTypesExample'))) :: type(ResolvedUserType(AllTypesExample))",
"GetMember(obj_base=CreateMetaType(base_type=UserType(name=Ident(text='AllTypesExample'))), name=Ident(text='name')) :: [StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))]",
- "CreateMetaType(base_type=UserType(name=Ident(text='AllTypesExample'))) :: MetaTypeType(ttype=ResolvedUserType(AllTypesExample))",
- "Literal(value=(GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='min')), GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='max'))), unit=None) :: TupleType(ttypes=[IntType(is_signed=True, size=16), IntType(is_signed=True, size=16)])",
+ "CreateMetaType(base_type=UserType(name=Ident(text='AllTypesExample'))) :: type(ResolvedUserType(AllTypesExample))",
+ "Literal(value=(GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='min')), GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='max'))), unit=None) :: (int16, int16)",
"GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='min')) :: [IntType(is_signed=True, size=16)]",
- 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: MetaTypeType(ttype=IntType(is_signed=True, size=16))',
+ 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: type(int16)',
"GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='max')) :: [IntType(is_signed=True, size=16)]",
- 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: MetaTypeType(ttype=IntType(is_signed=True, size=16))',
- "Literal(value=(GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='min')), GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='max'))), unit=None) :: TupleType(ttypes=[IntType(is_signed=True, size=16), IntType(is_signed=True, size=16)])",
+ 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: type(int16)',
+ "Literal(value=(GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='min')), GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='max'))), unit=None) :: (int16, int16)",
"GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='min')) :: [IntType(is_signed=True, size=16)]",
- 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: MetaTypeType(ttype=IntType(is_signed=True, size=16))',
+ 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: type(int16)',
"GetMember(obj_base=CreateMetaType(base_type=IntType(is_signed=True, size=16)), name=Ident(text='max')) :: [IntType(is_signed=True, size=16)]",
- 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: MetaTypeType(ttype=IntType(is_signed=True, size=16))',
+ 'CreateMetaType(base_type=IntType(is_signed=True, size=16)) :: type(int16)',
"CallFunction(callee=New(type_name=UserType(name=Ident(text='AllTypesExample'))), modifiers=[], args=[]) :: ResolvedUserType(AllTypesExample)",
"New(type_name=UserType(name=Ident(text='AllTypesExample'))) :: ResolvedUserType(AllTypesExample)",
"CallFunction(callee=New(type_name=UserType(name=Ident(text='AllTypesExample'))), modifiers=[], args=[]) :: ResolvedUserType(AllTypesExample)",
diff --git a/test/solidity_parser/ast/snapshots/snap_test_parsing.py b/test/solidity_parser/ast/snapshots/snap_test_parsing.py
index 8061d61..0ec0c16 100644
--- a/test/solidity_parser/ast/snapshots/snap_test_parsing.py
+++ b/test/solidity_parser/ast/snapshots/snap_test_parsing.py
@@ -12,7 +12,7 @@
]
snapshots['TestASTJSONCases::test_success_path_address_payable_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='address_payable.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='m'), ttype=MappingType(src=AddressType(is_payable=False), dst=AddressType(is_payable=True)), modifiers=[VisibilityModifier(kind=)], value=None), FunctionDefinition(name=Ident(text='m'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text='m'), ttype=MappingType(src=AddressType(is_payable=False), dst=AddressType(is_payable=True)), location=None))], modifiers=[], code=None, markers=[]), FunctionDefinition(name=Ident(text='m'), inputs=[Parameter(var=Var(name=None, ttype=AddressType(is_payable=False), location=None))], outputs=[Parameter(var=Var(name=None, ttype=AddressType(is_payable=True), location=None))], modifiers=[], code=None, markers=[]), FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='arg'), ttype=AddressType(is_payable=True), location=None))], outputs=[Parameter(var=Var(name=Ident(text='r'), ttype=AddressType(is_payable=True), location=None))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='a'), ttype=AddressType(is_payable=True), location=None), value=ArrayLoad(base=StateVarLoad(base=SelfObject(), name=Ident(text='m')), index=LocalVarLoad(var=Var(name=Ident(text='arg'), ttype=AddressType(is_payable=True), location=None)))), ExprStmt(expr=LocalVarStore(var=Var(name=Ident(text='r'), ttype=AddressType(is_payable=True), location=None), value=LocalVarLoad(var=Var(name=Ident(text='arg'), ttype=AddressType(is_payable=True), location=None)))), VarDecl(var=Var(name=Ident(text='c'), ttype=AddressType(is_payable=False), location=None), value=Cast(ttype=AddressType(is_payable=False), value=SelfObject())), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=SelfObject(), name=Ident(text='m')), index=LocalVarLoad(var=Var(name=Ident(text='c'), ttype=AddressType(is_payable=False), location=None)), value=Cast(ttype=AddressType(is_payable=True), value=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None))))], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='address_payable.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='m'), ttype=MappingType(src=AddressType(is_payable=False), dst=AddressType(is_payable=True), src_name=None, dst_name=None), modifiers=[VisibilityModifier(kind=)], value=None), FunctionDefinition(name=Ident(text='m'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text='m'), ttype=MappingType(src=AddressType(is_payable=False), dst=AddressType(is_payable=True), src_name=None, dst_name=None), location=None))], modifiers=[], code=None, markers=[]), FunctionDefinition(name=Ident(text='m'), inputs=[Parameter(var=Var(name=None, ttype=AddressType(is_payable=False), location=None))], outputs=[Parameter(var=Var(name=None, ttype=AddressType(is_payable=True), location=None))], modifiers=[], code=None, markers=[]), FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='arg'), ttype=AddressType(is_payable=True), location=None))], outputs=[Parameter(var=Var(name=Ident(text='r'), ttype=AddressType(is_payable=True), location=None))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='a'), ttype=AddressType(is_payable=True), location=None), value=ArrayLoad(base=StateVarLoad(base=SelfObject(), name=Ident(text='m')), index=LocalVarLoad(var=Var(name=Ident(text='arg'), ttype=AddressType(is_payable=True), location=None)))), ExprStmt(expr=LocalVarStore(var=Var(name=Ident(text='r'), ttype=AddressType(is_payable=True), location=None), value=LocalVarLoad(var=Var(name=Ident(text='arg'), ttype=AddressType(is_payable=True), location=None)))), VarDecl(var=Var(name=Ident(text='c'), ttype=AddressType(is_payable=False), location=None), value=Cast(ttype=AddressType(is_payable=False), value=SelfObject())), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=SelfObject(), name=Ident(text='m')), index=LocalVarLoad(var=Var(name=Ident(text='c'), ttype=AddressType(is_payable=False), location=None)), value=Cast(ttype=AddressType(is_payable=True), value=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None))))], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_array_type_name_sol 1'] = [
@@ -89,7 +89,7 @@
]
snapshots['TestASTJSONCases::test_success_path_event_with_variables_of_internal_types_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='event_with_variables_of_internal_types.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[EventDefinition(name=Ident(text='E'), inputs=[EventParameter(name=Ident(text=')]), is_indexed=False)], is_anonymous=False)], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_fallback_and_receive_ether_sol 1'] = [
@@ -105,7 +105,7 @@
]
snapshots['TestASTJSONCases::test_success_path_function_type_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='function_type.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='x'), ttype=FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)]), location=None))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)]), location=None))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='function_type.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='x'), ttype=FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)]), location=None))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FunctionType(inputs=[], outputs=[IntType(is_signed=False, size=256)], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)]), location=None))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_global_enum_sol 1'] = [
@@ -135,12 +135,12 @@
]
snapshots['TestASTJSONCases::test_success_path_long_type_name_identifier_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='long_type_name_identifier.sol', name=Ident(text='c'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='a'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), modifiers=[], value=None), FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=), value=StateVarLoad(base=SelfObject(), name=Ident(text='a')))], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='long_type_name_identifier.sol', name=Ident(text='c'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='a'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), modifiers=[], value=None), FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location()), value=StateVarLoad(base=SelfObject(), name=Ident(text='a')))], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_mappings_sol 1'] = [
GenericRepr("EnumDefinition(source_unit_name='mappings.sol$C', name=Ident(text='E'), values=[EnumMember(name=Ident(text='A')), EnumMember(name=Ident(text='B')), EnumMember(name=Ident(text='C'))])"),
- GenericRepr("ContractDefinition(source_unit_name='mappings.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='a'), ttype=MappingType(src=ResolvedUserType(C), dst=BoolType()), modifiers=[], value=None), StateVariableDeclaration(name=Ident(text='b'), ttype=MappingType(src=AddressType(is_payable=False), dst=BoolType()), modifiers=[], value=None), StateVariableDeclaration(name=Ident(text='c'), ttype=MappingType(src=ResolvedUserType(E), dst=BoolType()), modifiers=[], value=None), StateVariableDeclaration(name=Ident(text='d'), ttype=MappingType(src=AddressType(is_payable=False), dst=IntType(is_signed=False, size=256)), modifiers=[], value=None)], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='mappings.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='a'), ttype=MappingType(src=ResolvedUserType(C), dst=BoolType(), src_name=None, dst_name=None), modifiers=[], value=None), StateVariableDeclaration(name=Ident(text='b'), ttype=MappingType(src=AddressType(is_payable=False), dst=BoolType(), src_name=None, dst_name=None), modifiers=[], value=None), StateVariableDeclaration(name=Ident(text='c'), ttype=MappingType(src=ResolvedUserType(E), dst=BoolType(), src_name=None, dst_name=None), modifiers=[], value=None), StateVariableDeclaration(name=Ident(text='d'), ttype=MappingType(src=AddressType(is_payable=False), dst=IntType(is_signed=False, size=256), src_name=Ident(text='keyAddress'), dst_name=Ident(text='value')), modifiers=[], value=None)], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_modifier_definition_sol 1'] = [
@@ -156,7 +156,7 @@
]
snapshots['TestASTJSONCases::test_success_path_non_utf8_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='non_utf8.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=), value=Cast(ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), value=Cast(ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), value=Literal(value=255, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=8), unit=None))))], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='non_utf8.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()), value=Cast(ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), value=Cast(ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), value=Literal(value=255, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=8), unit=None))))], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_override_sol 1'] = [
@@ -177,11 +177,11 @@
]
snapshots['TestASTJSONCases::test_success_path_short_type_name_ref_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='short_type_name_ref.sol', name=Ident(text='c'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='rows'), ttype=ArrayType(base_type=ArrayType(base_type=IntType(is_signed=False, size=256))), location=), value=None)], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='short_type_name_ref.sol', name=Ident(text='c'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='rows'), ttype=ArrayType(base_type=ArrayType(base_type=IntType(is_signed=False, size=256))), location=Location()), value=None)], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_short_type_name_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='short_type_name.sol', name=Ident(text='c'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=), value=None)], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='short_type_name.sol', name=Ident(text='c'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location()), value=None)], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_smoke_sol 1'] = [
@@ -193,7 +193,7 @@
]
snapshots['TestASTJSONCases::test_success_path_string_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='string.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=), value=Literal(value='Hello World', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=11), unit=None))], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='string.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()), value=Literal(value='Hello World', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=11), unit=None))], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_struct_natspec_sol 1'] = [
@@ -207,7 +207,7 @@
]
snapshots['TestASTJSONCases::test_success_path_unicode_sol 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='unicode.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=), value=Literal(value='Hello 😃', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=7), unit=None))], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='unicode.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()), value=Literal(value='Hello 😃', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=7), unit=None))], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_used_errors_sol 1'] = [
@@ -221,7 +221,7 @@
GenericRepr("UserDefinedValueTypeDefinition(source_unit_name='userDefinedValueType.sol', name=Ident(text='MyUInt'), ttype=IntType(is_signed=False, size=256))"),
GenericRepr("UserDefinedValueTypeDefinition(source_unit_name='userDefinedValueType.sol$C', name=Ident(text='MyAddress'), ttype=AddressType(is_payable=False))"),
GenericRepr("UserDefinedValueTypeDefinition(source_unit_name='userDefinedValueType.sol$C', name=Ident(text='MyUInt'), ttype=IntType(is_signed=False, size=256))"),
- GenericRepr("ContractDefinition(source_unit_name='userDefinedValueType.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='m'), ttype=MappingType(src=ResolvedUserType(MyAddress), dst=ResolvedUserType(MyUInt)), modifiers=[VisibilityModifier(kind=)], value=None), FunctionDefinition(name=Ident(text='m'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text='m'), ttype=MappingType(src=ResolvedUserType(MyAddress), dst=ResolvedUserType(MyUInt)), location=None))], modifiers=[], code=None, markers=[]), FunctionDefinition(name=Ident(text='m'), inputs=[Parameter(var=Var(name=None, ttype=ResolvedUserType(MyAddress), location=None))], outputs=[Parameter(var=Var(name=None, ttype=ResolvedUserType(MyUInt), location=None))], modifiers=[], code=None, markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='userDefinedValueType.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='m'), ttype=MappingType(src=ResolvedUserType(MyAddress), dst=ResolvedUserType(MyUInt), src_name=None, dst_name=None), modifiers=[VisibilityModifier(kind=)], value=None), FunctionDefinition(name=Ident(text='m'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text='m'), ttype=MappingType(src=ResolvedUserType(MyAddress), dst=ResolvedUserType(MyUInt), src_name=None, dst_name=None), location=None))], modifiers=[], code=None, markers=[]), FunctionDefinition(name=Ident(text='m'), inputs=[Parameter(var=Var(name=None, ttype=ResolvedUserType(MyAddress), location=None))], outputs=[Parameter(var=Var(name=None, ttype=ResolvedUserType(MyUInt), location=None))], modifiers=[], code=None, markers=[])], type_overrides=[])")
]
snapshots['TestASTJSONCases::test_success_path_user_defined_operator_sol 1'] = [
@@ -241,72 +241,72 @@
]
snapshots['TestSemanticTestCases::sol 1'] = [
- GenericRepr("LibraryDefinition(source_unit_name='libraries/attached_public_library_function_accepting_calldata.sol.sol', name=Ident(text='D'), parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='g'), inputs=[Parameter(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None))])], is_unchecked=False), markers=[])], type_overrides=[])"),
- GenericRepr("ContractDefinition(source_unit_name='libraries/attached_public_library_function_accepting_calldata.sol.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None)), Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[DirectCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], ttype=ResolvedUserType(D), name=Ident(text='f')), DirectCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], ttype=ResolvedUserType(D), name=Ident(text='g'))])], is_unchecked=False), markers=[])], type_overrides=[LibraryOverride(overriden_type=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), library=ResolvedUserType(D))])")
+ GenericRepr("LibraryDefinition(source_unit_name='libraries/attached_public_library_function_accepting_calldata.sol.sol', name=Ident(text='D'), parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='g'), inputs=[Parameter(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None))])], is_unchecked=False), markers=[])], type_overrides=[])"),
+ GenericRepr("ContractDefinition(source_unit_name='libraries/attached_public_library_function_accepting_calldata.sol.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None)), Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=ByteType(), size=1), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[DirectCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], ttype=ResolvedUserType(D), name=Ident(text='f')), DirectCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='_x'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], ttype=ResolvedUserType(D), name=Ident(text='g'))])], is_unchecked=False), markers=[])], type_overrides=[LibraryOverride(overriden_type=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), library=ResolvedUserType(D))])")
]
snapshots['TestSemanticTestCases::test_debug 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='variables/public_state_overridding.sol', name=Ident(text='A'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='test'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=IntType(is_signed=False, size=256), location=None))], modifiers=[VisibilityModifier(kind=), VisibilityModifier(kind=)], code=Block(stmts=[Return(values=[Literal(value=5, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None)])], is_unchecked=False), markers=[])], type_overrides=[])"),
- GenericRepr("ContractDefinition(source_unit_name='variables/public_state_overridding.sol', name=Ident(text='X'), is_abstract=False, inherits=[InheritSpecifier(name=ResolvedUserType(A), args=[])], parts=[StateVariableDeclaration(name=Ident(text='test'), ttype=IntType(is_signed=False, size=256), modifiers=[VisibilityModifier(kind=), OverrideSpecifier(bases=[])], value=None), FunctionDefinition(name=Ident(text='test'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text='test'), ttype=IntType(is_signed=False, size=256), location=None))], modifiers=[], code=None, markers=[]), FunctionDefinition(name=Ident(text='set'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[ExprStmt(expr=StateVarStore(base=SelfObject(), name=Ident(text='test'), value=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)))], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("LibraryDefinition(source_unit_name='libraries/internal_library_function_attached_to_array_named_pop_push.sol', name=Ident(text='L'), parts=[FunctionDefinition(name=Ident(text='pop'), inputs=[Parameter(var=Var(name=Ident(text='a'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), location=Location()))], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='push'), inputs=[Parameter(var=Var(name=Ident(text='a'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), location=Location()))], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[], is_unchecked=False), markers=[])], type_overrides=[])"),
+ GenericRepr("ContractDefinition(source_unit_name='libraries/internal_library_function_attached_to_array_named_pop_push.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='test'), inputs=[], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='input'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), location=Location()), value=None), ExprStmt(expr=DirectCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='input'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), location=Location()))], ttype=ResolvedUserType(L), name=Ident(text='push'))), ExprStmt(expr=DirectCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='input'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), location=Location()))], ttype=ResolvedUserType(L), name=Ident(text='pop')))], is_unchecked=False), markers=[])], type_overrides=[LibraryOverride(overriden_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), library=ResolvedUserType(L))])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_dynamic_array 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_dynamic_array.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), TypeLiteral(ttype=TupleType(ttypes=[ArrayType(base_type=IntType(is_signed=False, size=256))]))], name='abi.decode', ttype=ArrayType(base_type=IntType(is_signed=False, size=256)))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_dynamic_array.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location()))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), TypeLiteral(ttype=TupleType(ttypes=[ArrayType(base_type=IntType(is_signed=False, size=256))]))], name='abi.decode', ttype=ArrayType(base_type=IntType(is_signed=False, size=256)))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_fixed_arrays 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_fixed_arrays.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='a'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=3), location=)), Parameter(var=Var(name=Ident(text='b'), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=2), size=3), location=)), Parameter(var=Var(name=Ident(text='i'), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text='j'), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text='k'), ttype=IntType(is_signed=False, size=256), location=None))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text=None), ttype=IntType(is_signed=False, size=256), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='a'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=3), location=)), index=LocalVarLoad(var=Var(name=Ident(text='i'), ttype=IntType(is_signed=False, size=256), location=None))), ArrayLoad(base=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=2), size=3), location=)), index=LocalVarLoad(var=Var(name=Ident(text='j'), ttype=IntType(is_signed=False, size=256), location=None))), index=LocalVarLoad(var=Var(name=Ident(text='k'), ttype=IntType(is_signed=False, size=256), location=None)))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_fixed_arrays.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='a'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=3), location=Location())), Parameter(var=Var(name=Ident(text='b'), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=2), size=3), location=Location())), Parameter(var=Var(name=Ident(text='i'), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text='j'), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text='k'), ttype=IntType(is_signed=False, size=256), location=None))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text=None), ttype=IntType(is_signed=False, size=256), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='a'), ttype=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=3), location=Location())), index=LocalVarLoad(var=Var(name=Ident(text='i'), ttype=IntType(is_signed=False, size=256), location=None))), ArrayLoad(base=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=16), size=2), size=3), location=Location())), index=LocalVarLoad(var=Var(name=Ident(text='j'), ttype=IntType(is_signed=False, size=256), location=None))), index=LocalVarLoad(var=Var(name=Ident(text='k'), ttype=IntType(is_signed=False, size=256), location=None)))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_static_array 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_static_array.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3), location=))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), TypeLiteral(ttype=TupleType(ttypes=[FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3)]))], name='abi.decode', ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_static_array.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3), location=Location()))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), TypeLiteral(ttype=TupleType(ttypes=[FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3)]))], name='abi.decode', ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_static_array_v2 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_static_array_v2.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3), location=))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), TypeLiteral(ttype=TupleType(ttypes=[FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3)]))], name='abi.decode', ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_static_array_v2.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3), location=Location()))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), TypeLiteral(ttype=TupleType(ttypes=[FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3)]))], name='abi.decode', ttype=FixedLengthArrayType(base_type=FixedLengthArrayType(base_type=IntType(is_signed=False, size=256), size=2), size=3))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_trivial 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_trivial.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=IntType(is_signed=False, size=256), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), TypeLiteral(ttype=TupleType(ttypes=[IntType(is_signed=False, size=256)]))], name='abi.decode', ttype=IntType(is_signed=False, size=256))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_trivial.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=IntType(is_signed=False, size=256), location=None))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), TypeLiteral(ttype=TupleType(ttypes=[IntType(is_signed=False, size=256)]))], name='abi.decode', ttype=IntType(is_signed=False, size=256))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_v2 1'] = [
GenericRepr("StructDefinition(source_unit_name='abiEncoderV1/abi_decode_v2.sol$C', name=Ident(text='S'), members=[StructMember(ttype=IntType(is_signed=False, size=256), name=Ident(text='a')), StructMember(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), name=Ident(text='b'))])"),
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_v2.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ResolvedUserType(S), location=))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=), value=None), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='a'), value=Literal(value=8, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b'), value=CreateMemoryArray(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), size=Literal(value=3, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b')), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=9, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b')), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=10, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b')), index=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None), value=Literal(value=11, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), Return(values=[BuiltInCall(named_args=[], args=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=))], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))), TypeLiteral(ttype=TupleType(ttypes=[ResolvedUserType(S)]))], name='abi.decode', ttype=ResolvedUserType(S))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_v2.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ResolvedUserType(S), location=Location()))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location()), value=None), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='a'), value=Literal(value=8, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b'), value=CreateMemoryArray(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), size=Literal(value=3, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b')), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=9, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b')), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=10, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b')), index=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None), value=Literal(value=11, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), Return(values=[BuiltInCall(named_args=[], args=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location()))], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))), TypeLiteral(ttype=TupleType(ttypes=[ResolvedUserType(S)]))], name='abi.decode', ttype=ResolvedUserType(S))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_v2_calldata 1'] = [
GenericRepr("StructDefinition(source_unit_name='abiEncoderV1/abi_decode_v2_calldata.sol$C', name=Ident(text='S'), members=[StructMember(ttype=IntType(is_signed=False, size=256), name=Ident(text='a')), StructMember(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), name=Ident(text='b'))])"),
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_v2_calldata.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ResolvedUserType(S), location=))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), TypeLiteral(ttype=TupleType(ttypes=[ResolvedUserType(S)]))], name='abi.decode', ttype=ResolvedUserType(S))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_v2_calldata.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ResolvedUserType(S), location=Location()))], modifiers=[VisibilityModifier(kind=), MutabilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), TypeLiteral(ttype=TupleType(ttypes=[ResolvedUserType(S)]))], name='abi.decode', ttype=ResolvedUserType(S))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_decode_v2_storage 1'] = [
GenericRepr("StructDefinition(source_unit_name='abiEncoderV1/abi_decode_v2_storage.sol$C', name=Ident(text='S'), members=[StructMember(ttype=IntType(is_signed=False, size=256), name=Ident(text='a')), StructMember(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), name=Ident(text='b'))])"),
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_v2_storage.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), modifiers=[], value=None), FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ResolvedUserType(S), location=))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=), value=None), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='a'), value=Literal(value=8, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b'), value=CreateMemoryArray(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), size=Literal(value=3, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b')), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=9, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b')), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=10, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=)), name=Ident(text='b')), index=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None), value=Literal(value=11, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=StateVarStore(base=SelfObject(), name=Ident(text='data'), value=BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=))], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))))), Return(values=[BuiltInCall(named_args=[], args=[StateVarLoad(base=SelfObject(), name=Ident(text='data')), TypeLiteral(ttype=TupleType(ttypes=[ResolvedUserType(S)]))], name='abi.decode', ttype=ResolvedUserType(S))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_decode_v2_storage.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), modifiers=[], value=None), FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=ResolvedUserType(S), location=Location()))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location()), value=None), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='a'), value=Literal(value=8, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=StateVarStore(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b'), value=CreateMemoryArray(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), size=Literal(value=3, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b')), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=9, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b')), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=10, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=ArrayStore(base=StateVarLoad(base=LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location())), name=Ident(text='b')), index=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None), value=Literal(value=11, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=4), unit=None))), ExprStmt(expr=StateVarStore(base=SelfObject(), name=Ident(text='data'), value=BuiltInCall(named_args=[], args=[LocalVarLoad(var=Var(name=Ident(text='s'), ttype=ResolvedUserType(S), location=Location()))], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))))), Return(values=[BuiltInCall(named_args=[], args=[StateVarLoad(base=SelfObject(), name=Ident(text='data')), TypeLiteral(ttype=TupleType(ttypes=[ResolvedUserType(S)]))], name='abi.decode', ttype=ResolvedUserType(S))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_encode 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_encode.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f0'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f1'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f2'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=), value=Literal(value='abc', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=3), unit=None)), Return(values=[BuiltInCall(named_args=[], args=[Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), LocalVarLoad(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f3'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text='r'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=), value=Literal(value='abc', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=3), unit=None)), ExprStmt(expr=LocalVarStore(var=Var(name=Ident(text='r'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=), value=BuiltInCall(named_args=[], args=[Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), LocalVarLoad(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))))), VarDecl(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=), value=Literal(value='def', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=3), unit=None)), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value='d', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=1), unit=None), op=), reason=None), ExprStmt(expr=ArrayStore(base=LocalVarLoad(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value='e', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=1), unit=None))), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value='e', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=1), unit=None), op=), reason=None)], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f4'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=FixedLengthArrayType(base_type=ByteType(), size=4), location=None), value=Literal(value='abcd', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=4), unit=None)), Return(values=[BuiltInCall(named_args=[], args=[Cast(ttype=FixedLengthArrayType(base_type=ByteType(), size=2), value=LocalVarLoad(var=Var(name=Ident(text='x'), ttype=FixedLengthArrayType(base_type=ByteType(), size=4), location=None)))], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_encode.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='f0'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f1'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f2'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()), value=Literal(value='abc', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=3), unit=None)), Return(values=[BuiltInCall(named_args=[], args=[Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), LocalVarLoad(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f3'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text='r'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()), value=Literal(value='abc', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=3), unit=None)), ExprStmt(expr=LocalVarStore(var=Var(name=Ident(text='r'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()), value=BuiltInCall(named_args=[], args=[Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), LocalVarLoad(var=Var(name=Ident(text='x'), ttype=StringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None)], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))))), VarDecl(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()), value=Literal(value='def', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=3), unit=None)), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value='d', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=1), unit=None), op=), reason=None), ExprStmt(expr=ArrayStore(base=LocalVarLoad(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value='e', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=1), unit=None))), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='y'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location())), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value='e', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=1), unit=None), op=), reason=None)], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f4'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=Location()))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='x'), ttype=FixedLengthArrayType(base_type=ByteType(), size=4), location=None), value=Literal(value='abcd', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=4), unit=None)), Return(values=[BuiltInCall(named_args=[], args=[Cast(ttype=FixedLengthArrayType(base_type=ByteType(), size=2), value=LocalVarLoad(var=Var(name=Ident(text='x'), ttype=FixedLengthArrayType(base_type=ByteType(), size=4), location=None)))], name='abi.encode', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_encode_call 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_encode_call.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='x'), ttype=BoolType(), modifiers=[], value=None), FunctionDefinition(name=Ident(text='c'), inputs=[Parameter(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=))], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[Require(condition=BinaryOp(left=LocalVarLoad(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None)), right=Literal(value=5, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None), op=), reason=None), Require(condition=BinaryOp(left=DynamicBuiltInValue(name='length', ttype=IntType(is_signed=False, size=256), base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=))), right=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None), op=), reason=None), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=)), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value=6, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None), op=), reason=None), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=)), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value=7, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None), op=), reason=None), ExprStmt(expr=StateVarStore(base=SelfObject(), name=Ident(text='x'), value=Literal(value=True, ttype=BoolType(), unit=None)))], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BoolType(), location=None))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None), value=Literal(value=5, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None)), VarDecl(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=), value=CreateMemoryArray(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), size=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None))), ExprStmt(expr=ArrayStore(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=)), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=6, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None))), ExprStmt(expr=ArrayStore(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=)), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=7, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None))), TupleVarDecl(vars=[Var(name=Ident(text='success'), ttype=BoolType(), location=None)], value=DynamicBuiltInCall(named_args=[], args=[BuiltInCall(named_args=[], args=[Literal(value='c(uint256,uint256[])', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=20), unit=None), LocalVarLoad(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None)), LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=))], name='abi.encodeWithSignature', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))], ttype=TupleType(ttypes=[BoolType(), BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))]), base=Cast(ttype=AddressType(is_payable=False), value=SelfObject()), name='call')), Require(condition=LocalVarLoad(var=Var(name=Ident(text='success'), ttype=BoolType(), location=None)), reason=None), Return(values=[StateVarLoad(base=SelfObject(), name=Ident(text='x'))])], is_unchecked=False), markers=[])], type_overrides=[])")
+ GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_encode_call.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[StateVariableDeclaration(name=Ident(text='x'), ttype=BoolType(), modifiers=[], value=None), FunctionDefinition(name=Ident(text='c'), inputs=[Parameter(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location()))], outputs=[], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[Require(condition=BinaryOp(left=LocalVarLoad(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None)), right=Literal(value=5, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None), op=), reason=None), Require(condition=BinaryOp(left=DynamicBuiltInValue(name='length', ttype=IntType(is_signed=False, size=256), base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location()))), right=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None), op=), reason=None), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location())), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value=6, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None), op=), reason=None), Require(condition=BinaryOp(left=ArrayLoad(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location())), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None)), right=Literal(value=7, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None), op=), reason=None), ExprStmt(expr=StateVarStore(base=SelfObject(), name=Ident(text='x'), value=Literal(value=True, ttype=BoolType(), unit=None)))], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='f'), inputs=[], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BoolType(), location=None))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[VarDecl(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None), value=Literal(value=5, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None)), VarDecl(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location()), value=CreateMemoryArray(ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), size=Literal(value=2, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=2), unit=None))), ExprStmt(expr=ArrayStore(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location())), index=Literal(value=0, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=6, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None))), ExprStmt(expr=ArrayStore(base=LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location())), index=Literal(value=1, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=1), unit=None), value=Literal(value=7, ttype=PreciseIntType(is_signed=False, size=8, real_bit_length=3), unit=None))), TupleVarDecl(vars=[Var(name=Ident(text='success'), ttype=BoolType(), location=None)], value=DynamicBuiltInCall(named_args=[], args=[BuiltInCall(named_args=[], args=[Literal(value='c(uint256,uint256[])', ttype=PreciseStringType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1), real_size=20), unit=None), LocalVarLoad(var=Var(name=Ident(text='a'), ttype=IntType(is_signed=False, size=256), location=None)), LocalVarLoad(var=Var(name=Ident(text='b'), ttype=ArrayType(base_type=IntType(is_signed=False, size=256)), location=Location()))], name='abi.encodeWithSignature', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))], ttype=TupleType(ttypes=[BoolType(), BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1))]), base=Cast(ttype=AddressType(is_payable=False), value=SelfObject()), name='call')), Require(condition=LocalVarLoad(var=Var(name=Ident(text='success'), ttype=BoolType(), location=None)), reason=None), Return(values=[StateVarLoad(base=SelfObject(), name=Ident(text='x'))])], is_unchecked=False), markers=[])], type_overrides=[])")
]
snapshots['TestSemanticTestCases::test_success_path_abiEncoderV1/abi_encode_calldata_slice 1'] = [
- GenericRepr("ContractDefinition(source_unit_name='abiEncoderV1/abi_encode_calldata_slice.sol', name=Ident(text='C'), is_abstract=False, inherits=[], parts=[FunctionDefinition(name=Ident(text='enc_packed_bytes'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), Parameter(var=Var(name=Ident(text='start'), ttype=IntType(is_signed=False, size=256), location=None)), Parameter(var=Var(name=Ident(text='end'), ttype=IntType(is_signed=False, size=256), location=None))], outputs=[Parameter(var=Var(name=Ident(text=None), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=))], modifiers=[VisibilityModifier(kind=)], code=Block(stmts=[Return(values=[BuiltInCall(named_args=[], args=[ArraySliceLoad(base=LocalVarLoad(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=)), start_index=LocalVarLoad(var=Var(name=Ident(text='start'), ttype=IntType(is_signed=False, size=256), location=None)), end_index=LocalVarLoad(var=Var(name=Ident(text='end'), ttype=IntType(is_signed=False, size=256), location=None)))], name='abi.encodePacked', ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)))])], is_unchecked=False), markers=[]), FunctionDefinition(name=Ident(text='enc_packed_bytes_reference'), inputs=[Parameter(var=Var(name=Ident(text='data'), ttype=BytesType(base_type=FixedLengthArrayType(base_type=ByteType(), size=1)), location=]