mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #9486 from ethereum/breaking
Merge breaking into develop.
This commit is contained in:
commit
2fece0724a
@ -10,7 +10,7 @@ include(EthPolicy)
|
||||
eth_policy()
|
||||
|
||||
# project name and version should be set after cmake_policy CMP0048
|
||||
set(PROJECT_VERSION "0.6.12")
|
||||
set(PROJECT_VERSION "0.7.0")
|
||||
# OSX target needed in order to support std::visit
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
|
||||
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)
|
||||
|
37
Changelog.md
37
Changelog.md
@ -1,3 +1,39 @@
|
||||
### 0.7.0 (unreleased)
|
||||
|
||||
Breaking changes:
|
||||
* Type Checker: Disallow virtual for library functions.
|
||||
* Constructors should not have visibility.
|
||||
* Deprecated dot syntax for `value` and `gas`.
|
||||
* Deprecated the identifier `now`.
|
||||
* Disallow `gwei` as identifier.
|
||||
* JSON AST: Removes members with ``null`` value from JSON output.
|
||||
* Parser: NatSpec comments on variables are only allowed for public state variables.
|
||||
* Type Checker: Disallow shifts by signed types.
|
||||
* Type Checker: Exponentiation and shifts of literals by non-literals will always use ``uint256`` or ``int256`` as a type.
|
||||
* Type Checker: Disallow structs and arrays in memory or calldata if they contain nested mappings.
|
||||
* Type Checker: Disallow assignments to state variables that contain nested mappings.
|
||||
* Type checker: Disallow events with same name and parameter types in inheritance hierarchy.
|
||||
* ``using A for B`` only affects the contract it is mentioned in and not all derived contracts
|
||||
* Inline Assembly: Disallow `.` in user-defined function and variable names.
|
||||
* Inline Assembly: Slot and offset of storage pointer variable ``x`` are accessed via ``x.slot`` and ``x.offset`` instead of ``x_slot`` and ``x_offset``.
|
||||
* Remove the finney and szabo denominations.
|
||||
|
||||
Language Features:
|
||||
* State mutability: Do not issue recommendation for stricter mutability for virtual functions but do issue it for functions that override.
|
||||
* Yul: Disallow EVM instruction `pc()`.
|
||||
* Yul: Disallow consecutive and trailing dots in identifiers. Leading dots were already disallowed.
|
||||
* Inheritance: Allow overrides to have stricter state mutability: ``view`` can override ``nonpayable`` and ``pure`` can override ``view``.
|
||||
|
||||
Compiler Features:
|
||||
* Variable declarations using the ``var`` keyword are not recognized anymore.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
* NatSpec: Constructors and functions have consistent userdoc output.
|
||||
* Inheritance: Disallow public state variables overwriting ``pure`` functions.
|
||||
* State Mutability: Constant public state variables are considered ``pure`` functions.
|
||||
|
||||
|
||||
### 0.6.12 (2020-07-22)
|
||||
|
||||
Language Features:
|
||||
@ -29,6 +65,7 @@ Build System:
|
||||
|
||||
### 0.6.11 (2020-07-07)
|
||||
|
||||
|
||||
Language Features:
|
||||
* General: Add unit denomination ``gwei``
|
||||
* Yul: Support ``linkersymbol`` builtin in standalone assembly mode to refer to library addresses.
|
||||
|
@ -37,7 +37,7 @@ found in the [Solidity documentation](https://solidity.readthedocs.io/en/latest/
|
||||
A "Hello World" program in Solidity is of even less use than in other languages, but still:
|
||||
|
||||
```solidity
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract HelloWorld {
|
||||
function helloWorld() external pure returns (string memory) {
|
||||
|
@ -311,7 +311,7 @@ This will no longer compile with Solidity v0.5.0. However, you can define a comp
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
interface OldContract {
|
||||
function someOldFunction(uint8 a) external;
|
||||
function anotherOldFunction() external returns (bool);
|
||||
@ -329,7 +329,7 @@ Given the interface defined above, you can now easily use the already deployed p
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
interface OldContract {
|
||||
function someOldFunction(uint8 a) external;
|
||||
|
124
docs/070-breaking-changes.rst
Normal file
124
docs/070-breaking-changes.rst
Normal file
@ -0,0 +1,124 @@
|
||||
********************************
|
||||
Solidity v0.7.0 Breaking Changes
|
||||
********************************
|
||||
|
||||
This section highlights the main breaking changes introduced in Solidity
|
||||
version 0.7.0, along with the reasoning behind the changes and how to update
|
||||
affected code.
|
||||
For the full list check
|
||||
`the release changelog <https://github.com/ethereum/solidity/releases/tag/v0.7.0>`_.
|
||||
|
||||
|
||||
Silent Changes of the Semantics
|
||||
===============================
|
||||
|
||||
* Exponentiation and shifts of literals by non-literals (e.g. ``1 << x`` or ``2 ** x``)
|
||||
will always use either the type ``uint256`` (for non-negative literals) or
|
||||
``int256`` (for negative literals) to perform the operation.
|
||||
Previously, the operation was performed in the type of the shift amount / the
|
||||
exponent which can be misleading.
|
||||
|
||||
|
||||
Changes to the Syntax
|
||||
=====================
|
||||
|
||||
* In external function and contract creation calls, Ether and gas is now specified using a new syntax:
|
||||
``x.f{gas: 10000, value: 2 ether}(arg1, arg2)``.
|
||||
The old syntax -- ``x.f.gas(10000).value(2 ether)(arg1, arg2)`` -- will cause an error.
|
||||
* The global variable ``now`` is deprecated, ``block.timestamp`` should be used instead.
|
||||
The single identifier ``now`` is too generic for a global variable and could give the impression
|
||||
that it changes during transaction processing, whereas ``block.timestamp`` correctly
|
||||
reflects the fact that it is just a property of the block.
|
||||
* NatSpec comments on variables are only allowed for public state variables and not
|
||||
for local or internal variables.
|
||||
|
||||
* The token ``gwei`` is a keyword now (used to specify, e.g. ``2 gwei`` as a number)
|
||||
and cannot be used as an identifier.
|
||||
|
||||
* State Mutability: The state mutability of functions can now be restricted during inheritance:
|
||||
Functions with default state mutability can be overridden by ``pure`` and ``view`` functions
|
||||
while ``view`` functions can be overridden by ``pure`` functions.
|
||||
At the same time, public state variables are considered ``view`` and even ``pure``
|
||||
if they are constants.
|
||||
|
||||
|
||||
|
||||
Inline Assembly
|
||||
---------------
|
||||
|
||||
* Disallow ``.`` in user-defined function and variable names in inline assembly.
|
||||
It is still valid if you use Solidity in Yul-only mode.
|
||||
|
||||
* Slot and offset of storage pointer variable ``x`` are accessed via ``x.slot``
|
||||
and ``x.offset`` instead of ``x_slot`` and ``x_offset``.
|
||||
|
||||
Removal of Unused or Unsafe Features
|
||||
====================================
|
||||
|
||||
Mappings outside Storage
|
||||
------------------------
|
||||
|
||||
* If a struct or array contains a mapping, it can only be used in storage.
|
||||
Previously, mapping members were silently skipped in memory, which
|
||||
is confusing and error-prone.
|
||||
|
||||
* Assignments to structs or arrays in storage does not work if they contain
|
||||
mappings.
|
||||
Previously, mappings were silently skipped during the copy operation, which
|
||||
is misleading and error-prone.
|
||||
|
||||
Functions and Events
|
||||
--------------------
|
||||
|
||||
* Visibility (``public`` / ``external``) is not needed for constructors anymore:
|
||||
To prevent a contract from being created, it can be marked ``abstract``.
|
||||
This makes the visibility concept for constructors obsolete.
|
||||
|
||||
* Type Checker: Disallow ``virtual`` for library functions:
|
||||
Since libraries cannot be inherited from, library functions should not be virtual.
|
||||
|
||||
* Multiple events with the same name and parameter types in the same
|
||||
inheritance hierarchy are disallowed.
|
||||
|
||||
* ``using A for B`` only affects the contract it is mentioned in.
|
||||
Previously, the effect was inherited. Now, you have to repeat the ``using``
|
||||
statement in all derived contracts that make use of the feature.
|
||||
|
||||
Expressions
|
||||
-----------
|
||||
|
||||
* Shifts by signed types are disallowed.
|
||||
Previously, shifts by negative amounts were allowed, but reverted at runtime.
|
||||
|
||||
* The ``finney`` and ``szabo`` denominations are removed.
|
||||
They are rarely used and do not make the actual amount readily visible. Instead, explicit
|
||||
values like ``1e20`` or the very common ``gwei`` can be used.
|
||||
|
||||
Declarations
|
||||
------------
|
||||
|
||||
* The keyword ``var`` cannot be used anymore.
|
||||
Previously, this keyword would parse but result in a type error and
|
||||
a suggestion about which type to use. Now, it results in a parser error.
|
||||
|
||||
Interface Changes
|
||||
=================
|
||||
|
||||
* JSON AST: Members with value ``null`` are removed from JSON output.
|
||||
* NatSpec: Constructors and functions have consistent userdoc output.
|
||||
|
||||
|
||||
How to update your code
|
||||
=======================
|
||||
|
||||
This section gives detailed instructions on how to update prior code for every breaking change.
|
||||
|
||||
* Change ``x.f.value(...)()`` to ``x.f{value: ...}()``. Similarly ``(new C).value(...)()`` to
|
||||
``new C{value: ...}()`` and ``x.f.gas(...).value(...)()`` to ``x.f{gas: ..., value: ...}()``.
|
||||
* Change ``now`` to ``block.timestamp``.
|
||||
* Change types of right operand in shift operators to unsigned types. For example change ``x >> (256 - y)`` to
|
||||
``x >> uint(256 - y)``.
|
||||
* Repeat the ``using A for B`` statements in all derived contracts if needed.
|
||||
* Remove the ``public`` keyword from every constructor.
|
||||
* Remove the ``internal`` keyword from every constructor and add ``abstract`` to the contract (if not already present).
|
||||
* Change ``_slot`` and ``_offset`` suffixes in inline assembly to ``.slot`` and ``.offset``, respectively.
|
@ -306,7 +306,7 @@ assemblyBlock
|
||||
: '{' assemblyItem* '}' ;
|
||||
|
||||
assemblyExpression
|
||||
: assemblyCall | assemblyLiteral ;
|
||||
: assemblyCall | assemblyLiteral | assemblyIdentifier ;
|
||||
|
||||
assemblyCall
|
||||
: ( 'return' | 'address' | 'byte' | identifier ) ( '(' assemblyExpression? ( ',' assemblyExpression )* ')' )? ;
|
||||
@ -318,7 +318,10 @@ assemblyAssignment
|
||||
: assemblyIdentifierList ':=' assemblyExpression ;
|
||||
|
||||
assemblyIdentifierList
|
||||
: identifier ( ',' identifier )* ;
|
||||
: assemblyIdentifier ( ',' assemblyIdentifier )* ;
|
||||
|
||||
assemblyIdentifier
|
||||
: identifier ( '.' identifier )* ;
|
||||
|
||||
assemblyStackAssignment
|
||||
: '=:' identifier ;
|
||||
@ -358,11 +361,12 @@ assemblyType
|
||||
subAssembly
|
||||
: 'assembly' identifier assemblyBlock ;
|
||||
|
||||
// 'finney' and 'szabo' are no longer supported as denominations by latest Solidity.
|
||||
numberLiteral
|
||||
: (DecimalNumber | HexNumber) (NumberUnit | Gwei)?;
|
||||
: (DecimalNumber | HexNumber) (NumberUnit | Gwei | Finney | Szabo)?;
|
||||
|
||||
identifier
|
||||
: (Gwei | 'from' | 'calldata' | 'address' | Identifier) ;
|
||||
: (Gwei | Finney | Szabo | 'from' | 'calldata' | 'address' | Identifier) ;
|
||||
|
||||
BooleanLiteral
|
||||
: 'true' | 'false' ;
|
||||
@ -382,10 +386,12 @@ HexDigits
|
||||
: HexCharacter ( '_'? HexCharacter )* ;
|
||||
|
||||
NumberUnit
|
||||
: 'wei' | 'szabo' | 'finney' | 'ether'
|
||||
: 'wei' | 'ether'
|
||||
| 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years' ;
|
||||
|
||||
Gwei: 'gwei' ;
|
||||
Szabo: 'szabo' ;
|
||||
Finney: 'finney' ;
|
||||
|
||||
HexLiteralFragment
|
||||
: 'hex' (('"' HexDigits? '"') | ('\'' HexDigits? '\'')) ;
|
||||
|
@ -233,7 +233,7 @@ Given the contract:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract Foo {
|
||||
function bar(bytes3[2] memory) public pure {}
|
||||
@ -537,11 +537,11 @@ For example,
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
|
||||
contract Test {
|
||||
constructor() public { b = hex"12345678901234567890123456789012"; }
|
||||
constructor() { b = hex"12345678901234567890123456789012"; }
|
||||
event Event(uint indexed a, bytes32 b);
|
||||
event Event2(uint indexed a, bytes32 b);
|
||||
function foo(uint a) public { emit Event(a, b); }
|
||||
@ -586,7 +586,7 @@ As an example, the code
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.19 <0.7.0;
|
||||
pragma solidity >=0.4.19 <0.8.0;
|
||||
pragma experimental ABIEncoderV2;
|
||||
|
||||
contract Test {
|
||||
|
@ -42,7 +42,7 @@ without a compiler change.
|
||||
.. code::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
library GetCode {
|
||||
function at(address _addr) public view returns (bytes memory o_code) {
|
||||
@ -68,7 +68,7 @@ efficient code, for example:
|
||||
.. code::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
|
||||
library VectorSum {
|
||||
@ -132,14 +132,15 @@ For local storage variables or state variables, a single Yul identifier
|
||||
is not sufficient, since they do not necessarily occupy a single full storage slot.
|
||||
Therefore, their "address" is composed of a slot and a byte-offset
|
||||
inside that slot. To retrieve the slot pointed to by the variable ``x``, you
|
||||
use ``x_slot``, and to retrieve the byte-offset you use ``x_offset``.
|
||||
use ``x.slot``, and to retrieve the byte-offset you use ``x.offset``.
|
||||
Using ``x`` itself will result in an error.
|
||||
|
||||
Local Solidity variables are available for assignments, for example:
|
||||
|
||||
.. code::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract C {
|
||||
uint b;
|
||||
@ -147,7 +148,7 @@ Local Solidity variables are available for assignments, for example:
|
||||
assembly {
|
||||
// We ignore the storage slot offset, we know it is zero
|
||||
// in this special case.
|
||||
r := mul(x, sload(b_slot))
|
||||
r := mul(x, sload(b.slot))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,20 +165,21 @@ Local Solidity variables are available for assignments, for example:
|
||||
``assembly { signextend(<num_bytes_of_x_minus_one>, x) }``
|
||||
|
||||
|
||||
Since Solidity 0.6.0 the name of a inline assembly variable may not end in ``_offset`` or ``_slot``
|
||||
and it may not shadow any declaration visible in the scope of the inline assembly block
|
||||
(including variable, contract and function declarations). Similarly, if the name of a declared
|
||||
variable contains a dot ``.``, the prefix up to the ``.`` may not conflict with any
|
||||
declaration visible in the scope of the inline assembly block.
|
||||
Since Solidity 0.6.0 the name of a inline assembly variable may not
|
||||
shadow any declaration visible in the scope of the inline assembly block
|
||||
(including variable, contract and function declarations).
|
||||
|
||||
Since Solidity 0.7.0, variables and functions declared inside the
|
||||
inline assembly block may not contain ``.``, but using ``.`` is
|
||||
valid to access Solidity variables from outside the inline assembly block.
|
||||
|
||||
Assignments are possible to assembly-local variables and to function-local
|
||||
variables. Take care that when you assign to variables that point to
|
||||
memory or storage, you will only change the pointer and not the data.
|
||||
|
||||
You can assign to the ``_slot`` part of a local storage variable pointer.
|
||||
For these (structs, arrays or mappings), the ``_offset`` part is always zero.
|
||||
It is not possible to assign to the ``_slot`` or ``_offset`` part of a state variable,
|
||||
You can assign to the ``.slot`` part of a local storage variable pointer.
|
||||
For these (structs, arrays or mappings), the ``.offset`` part is always zero.
|
||||
It is not possible to assign to the ``.slot`` or ``.offset`` part of a state variable,
|
||||
though.
|
||||
|
||||
|
||||
|
@ -67,7 +67,7 @@ The following is the order of precedence for operators, listed in order of evalu
|
||||
| *15* | Comma operator | ``,`` |
|
||||
+------------+-------------------------------------+--------------------------------------------+
|
||||
|
||||
.. index:: assert, block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin, revert, require, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
|
||||
.. index:: assert, block, coinbase, difficulty, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin, revert, require, keccak256, ripemd160, sha256, ecrecover, addmod, mulmod, cryptography, this, super, selfdestruct, balance, send
|
||||
|
||||
Global Variables
|
||||
================
|
||||
@ -91,7 +91,6 @@ Global Variables
|
||||
- ``msg.data`` (``bytes``): complete calldata
|
||||
- ``msg.sender`` (``address payable``): sender of the message (current call)
|
||||
- ``msg.value`` (``uint``): number of wei sent with the message
|
||||
- ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``)
|
||||
- ``tx.gasprice`` (``uint``): gas price of the transaction
|
||||
- ``tx.origin`` (``address payable``): sender of the transaction (full call chain)
|
||||
- ``assert(bool condition)``: abort execution and revert state changes if condition is ``false`` (use for internal error)
|
||||
@ -126,7 +125,7 @@ Global Variables
|
||||
- ``type(T).max`` (``T``): the maximum value representable by the integer type ``T``, see :ref:`Type Information<meta-type>`.
|
||||
|
||||
.. note::
|
||||
Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness,
|
||||
Do not rely on ``block.timestamp`` or ``blockhash`` as a source of randomness,
|
||||
unless you know what you are doing.
|
||||
|
||||
Both the timestamp and the block hash can be influenced by miners to some degree.
|
||||
@ -146,6 +145,8 @@ Global Variables
|
||||
In version 0.5.0, the following aliases were removed: ``suicide`` as alias for ``selfdestruct``,
|
||||
``msg.gas`` as alias for ``gasleft``, ``block.blockhash`` as alias for ``blockhash`` and
|
||||
``sha3`` as alias for ``keccak256``.
|
||||
.. note::
|
||||
In version 0.7.0, the alias ``now`` (for ``block.timestamp``) was removed.
|
||||
|
||||
.. index:: visibility, public, private, external, internal
|
||||
|
||||
|
@ -28,7 +28,7 @@ you receive the funds of the person who is now the richest.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract WithdrawalContract {
|
||||
address public richest;
|
||||
@ -36,7 +36,7 @@ you receive the funds of the person who is now the richest.
|
||||
|
||||
mapping (address => uint) pendingWithdrawals;
|
||||
|
||||
constructor() public payable {
|
||||
constructor() payable {
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
}
|
||||
@ -62,13 +62,13 @@ This is as opposed to the more intuitive sending pattern:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract SendContract {
|
||||
address payable public richest;
|
||||
uint public mostSent;
|
||||
|
||||
constructor() public payable {
|
||||
constructor() payable {
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
}
|
||||
@ -124,14 +124,14 @@ restrictions highly readable.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
contract AccessRestriction {
|
||||
// These will be assigned at the construction
|
||||
// phase, where `msg.sender` is the account
|
||||
// creating this contract.
|
||||
address public owner = msg.sender;
|
||||
uint public creationTime = now;
|
||||
uint public creationTime = block.timestamp;
|
||||
|
||||
// Modifiers can be used to change
|
||||
// the body of a function.
|
||||
@ -162,7 +162,7 @@ restrictions highly readable.
|
||||
|
||||
modifier onlyAfter(uint _time) {
|
||||
require(
|
||||
now >= _time,
|
||||
block.timestamp >= _time,
|
||||
"Function called too early."
|
||||
);
|
||||
_;
|
||||
@ -277,7 +277,7 @@ function finishes.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
contract StateMachine {
|
||||
enum Stages {
|
||||
@ -291,7 +291,7 @@ function finishes.
|
||||
// This is the current stage.
|
||||
Stages public stage = Stages.AcceptingBlindedBids;
|
||||
|
||||
uint public creationTime = now;
|
||||
uint public creationTime = block.timestamp;
|
||||
|
||||
modifier atStage(Stages _stage) {
|
||||
require(
|
||||
@ -310,10 +310,10 @@ function finishes.
|
||||
// will not take the new stage into account.
|
||||
modifier timedTransitions() {
|
||||
if (stage == Stages.AcceptingBlindedBids &&
|
||||
now >= creationTime + 10 days)
|
||||
block.timestamp >= creationTime + 10 days)
|
||||
nextStage();
|
||||
if (stage == Stages.RevealBids &&
|
||||
now >= creationTime + 12 days)
|
||||
block.timestamp >= creationTime + 12 days)
|
||||
nextStage();
|
||||
// The other stages transition by transaction
|
||||
_;
|
||||
|
@ -14,7 +14,7 @@ defined as abstract, because the function ``utterance()`` was defined, but no im
|
||||
provided (no implementation body ``{ }`` was given).::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
abstract contract Feline {
|
||||
function utterance() public virtual returns (bytes32);
|
||||
@ -24,14 +24,14 @@ Such abstract contracts can not be instantiated directly. This is also true, if
|
||||
all defined functions. The usage of an abstract contract as a base class is shown in the following example::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
abstract contract Feline {
|
||||
function utterance() public virtual returns (bytes32);
|
||||
function utterance() public pure virtual returns (bytes32);
|
||||
}
|
||||
|
||||
contract Cat is Feline {
|
||||
function utterance() public override returns (bytes32) { return "miaow"; }
|
||||
function utterance() public pure override returns (bytes32) { return "miaow"; }
|
||||
}
|
||||
|
||||
If a contract inherits from an abstract contract and does not implement all non-implemented
|
||||
|
@ -18,7 +18,7 @@ Not all types for constants and immutables are implemented at this time. The onl
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >0.6.4 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract C {
|
||||
uint constant X = 32**22 + 8;
|
||||
@ -28,7 +28,7 @@ Not all types for constants and immutables are implemented at this time. The onl
|
||||
uint immutable maxBalance;
|
||||
address immutable owner = msg.sender;
|
||||
|
||||
constructor(uint _decimals, address _reference) public {
|
||||
constructor(uint _decimals, address _reference) {
|
||||
decimals = _decimals;
|
||||
// Assignments to immutables can even access the environment.
|
||||
maxBalance = _reference.balance;
|
||||
@ -45,7 +45,7 @@ Constant
|
||||
|
||||
For ``constant`` variables, the value has to be a constant at compile time and it has to be
|
||||
assigned where the variable is declared. Any expression
|
||||
that accesses storage, blockchain data (e.g. ``now``, ``address(this).balance`` or
|
||||
that accesses storage, blockchain data (e.g. ``block.timestamp``, ``address(this).balance`` or
|
||||
``block.number``) or
|
||||
execution data (``msg.value`` or ``gasleft()``) or makes calls to external contracts is disallowed. Expressions
|
||||
that might have a side-effect on memory allocation are allowed, but those that
|
||||
|
@ -35,7 +35,7 @@ This means that cyclic creation dependencies are impossible.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
|
||||
contract OwnedToken {
|
||||
@ -48,7 +48,7 @@ This means that cyclic creation dependencies are impossible.
|
||||
|
||||
// This is the constructor which registers the
|
||||
// creator and the assigned name.
|
||||
constructor(bytes32 _name) public {
|
||||
constructor(bytes32 _name) {
|
||||
// State variables are accessed via their name
|
||||
// and not via e.g. `this.owner`. Functions can
|
||||
// be accessed directly or through `this.f`,
|
||||
|
@ -66,7 +66,7 @@ is that they are cheaper to deploy and call.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.21 <0.7.0;
|
||||
pragma solidity >=0.4.21 <0.8.0;
|
||||
|
||||
contract ClientReceipt {
|
||||
event Deposit(
|
||||
@ -140,7 +140,7 @@ as topics. The event call above can be performed in the same way as
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.10 <0.7.0;
|
||||
pragma solidity >=0.4.10 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function f() public payable {
|
||||
|
@ -18,10 +18,10 @@ if they are marked ``virtual``. For details, please see
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract owned {
|
||||
constructor() public { owner = msg.sender; }
|
||||
constructor() { owner = msg.sender; }
|
||||
address payable owner;
|
||||
|
||||
// This contract only defines a modifier but does not use
|
||||
@ -63,7 +63,7 @@ if they are marked ``virtual``. For details, please see
|
||||
mapping (address => bool) registeredAddresses;
|
||||
uint price;
|
||||
|
||||
constructor(uint initialPrice) public { price = initialPrice; }
|
||||
constructor(uint initialPrice) { price = initialPrice; }
|
||||
|
||||
// It is important to also provide the
|
||||
// `payable` keyword here, otherwise the function will
|
||||
|
@ -24,7 +24,7 @@ For example, if you want your contract to accept one kind of external call
|
||||
with two integers, you would use something like the following::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract Simple {
|
||||
uint sum;
|
||||
@ -57,7 +57,7 @@ For example, suppose you want to return two results: the sum and the product of
|
||||
two integers passed as function parameters, then you use something like::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract Simple {
|
||||
function arithmetic(uint _a, uint _b)
|
||||
@ -82,7 +82,7 @@ or you can provide return values
|
||||
statement::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract Simple {
|
||||
function arithmetic(uint _a, uint _b)
|
||||
@ -146,11 +146,11 @@ The following statements are considered modifying the state:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function f(uint a, uint b) public view returns (uint) {
|
||||
return a * (b + 42) + now;
|
||||
return a * (b + 42) + block.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ In addition to the list of state modifying statements explained above, the follo
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function f(uint a, uint b) public pure returns (uint) {
|
||||
@ -286,7 +286,7 @@ Below you can see an example of a Sink contract that uses function ``receive``.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
// This contract keeps all Ether sent to it with no way
|
||||
// to get it back.
|
||||
@ -342,7 +342,7 @@ operations as long as there is enough gas passed on to it.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.2 <0.7.0;
|
||||
pragma solidity >=0.6.2 <0.8.0;
|
||||
|
||||
contract Test {
|
||||
// This function is called for all messages sent to
|
||||
@ -415,7 +415,7 @@ The following example shows overloading of the function
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract A {
|
||||
function f(uint _in) public pure returns (uint out) {
|
||||
@ -434,7 +434,7 @@ externally visible functions differ by their Solidity types but not by their ext
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
// This will not compile
|
||||
contract A {
|
||||
@ -468,7 +468,7 @@ candidate, resolution fails.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract A {
|
||||
function f(uint8 _in) public pure returns (uint8 out) {
|
||||
|
@ -39,11 +39,11 @@ Details are given in the following example.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
|
||||
contract Owned {
|
||||
constructor() public { owner = msg.sender; }
|
||||
constructor() { owner = msg.sender; }
|
||||
address payable owner;
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ Details are given in the following example.
|
||||
// also a base class of `Destructible`, yet there is only a single
|
||||
// instance of `owned` (as for virtual inheritance in C++).
|
||||
contract Named is Owned, Destructible {
|
||||
constructor(bytes32 name) public {
|
||||
constructor(bytes32 name) {
|
||||
Config config = Config(0xD5f9D8D94886E70b06E474c3fB14Fd43E2f23970);
|
||||
NameReg(config.lookup(1)).register(name);
|
||||
}
|
||||
@ -106,8 +106,8 @@ Details are given in the following example.
|
||||
|
||||
|
||||
// If a constructor takes an argument, it needs to be
|
||||
// provided in the header (or modifier-invocation-style at
|
||||
// the constructor of the derived contract (see below)).
|
||||
// provided in the header or modifier-invocation-style at
|
||||
// the constructor of the derived contract (see below).
|
||||
contract PriceFeed is Owned, Destructible, Named("GoldFeed") {
|
||||
function updateInfo(uint newInfo) public {
|
||||
if (msg.sender == owner) info = newInfo;
|
||||
@ -127,10 +127,10 @@ destruction request. The way this is done is problematic, as
|
||||
seen in the following example::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract owned {
|
||||
constructor() public { owner = msg.sender; }
|
||||
constructor() { owner = msg.sender; }
|
||||
address payable owner;
|
||||
}
|
||||
|
||||
@ -157,10 +157,10 @@ explicitly in the final override, but this function will bypass
|
||||
``Base1.destroy``. The way around this is to use ``super``::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract owned {
|
||||
constructor() public { owner = msg.sender; }
|
||||
constructor() { owner = msg.sender; }
|
||||
address payable owner;
|
||||
}
|
||||
|
||||
@ -203,23 +203,29 @@ Function Overriding
|
||||
|
||||
Base functions can be overridden by inheriting contracts to change their
|
||||
behavior if they are marked as ``virtual``. The overriding function must then
|
||||
use the ``override`` keyword in the function header as shown in this example:
|
||||
use the ``override`` keyword in the function header.
|
||||
The overriding function may only change the visibility of the overridden function from ``external`` to ``public``.
|
||||
The mutability may be changed to a more strict one following the order:
|
||||
``nonpayable`` can be overridden by ``view`` and ``pure``. ``view`` can be overridden by ``pure``.
|
||||
``payable`` is an exception and cannot be changed to any other mutability.
|
||||
|
||||
The following example demonstrates changing mutability and visibility:
|
||||
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract Base
|
||||
{
|
||||
function foo() virtual public {}
|
||||
function foo() virtual external view {}
|
||||
}
|
||||
|
||||
contract Middle is Base {}
|
||||
|
||||
contract Inherited is Middle
|
||||
{
|
||||
function foo() public override {}
|
||||
function foo() override public pure {}
|
||||
}
|
||||
|
||||
For multiple inheritance, the most derived base contracts that define the same
|
||||
@ -232,7 +238,7 @@ bases, it has to explicitly override it:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract Base1
|
||||
{
|
||||
@ -259,7 +265,7 @@ that already overrides all other functions.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract A { function f() public pure{} }
|
||||
contract B is A {}
|
||||
@ -300,11 +306,11 @@ of the variable:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract A
|
||||
{
|
||||
function f() external pure virtual returns(uint) { return 5; }
|
||||
function f() external view virtual returns(uint) { return 5; }
|
||||
}
|
||||
|
||||
contract B is A
|
||||
@ -332,7 +338,7 @@ and the ``override`` keyword must be used in the overriding modifier:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract Base
|
||||
{
|
||||
@ -351,7 +357,7 @@ explicitly:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract Base1
|
||||
{
|
||||
@ -392,33 +398,39 @@ and all functions that are reachable from there through function calls.
|
||||
It does not include the constructor code or internal functions that are
|
||||
only called from the constructor.
|
||||
|
||||
Constructor functions can be either ``public`` or ``internal``. If there is no
|
||||
If there is no
|
||||
constructor, the contract will assume the default constructor, which is
|
||||
equivalent to ``constructor() public {}``. For example:
|
||||
equivalent to ``constructor() {}``. For example:
|
||||
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract A {
|
||||
abstract contract A {
|
||||
uint public a;
|
||||
|
||||
constructor(uint _a) internal {
|
||||
constructor(uint _a) {
|
||||
a = _a;
|
||||
}
|
||||
}
|
||||
|
||||
contract B is A(1) {
|
||||
constructor() public {}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
A constructor set as ``internal`` causes the contract to be marked as :ref:`abstract <abstract-contract>`.
|
||||
You can use internal parameters in a constructor (for example storage pointers). In this case,
|
||||
the contract has to be marked :ref:`abstract <abstract-contract>`, because these parameters
|
||||
cannot be assigned valid values from outside but only through the constructors of derived contracts.
|
||||
|
||||
.. warning ::
|
||||
Prior to version 0.4.22, constructors were defined as functions with the same name as the contract.
|
||||
This syntax was deprecated and is not allowed anymore in version 0.5.0.
|
||||
|
||||
.. warning ::
|
||||
Prior to version 0.7.0, you had to specify the visibility of constructors as either
|
||||
``internal`` or ``public``.
|
||||
|
||||
|
||||
.. index:: ! base;constructor
|
||||
|
||||
@ -430,21 +442,21 @@ linearization rules explained below. If the base constructors have arguments,
|
||||
derived contracts need to specify all of them. This can be done in two ways::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract Base {
|
||||
uint x;
|
||||
constructor(uint _x) public { x = _x; }
|
||||
constructor(uint _x) { x = _x; }
|
||||
}
|
||||
|
||||
// Either directly specify in the inheritance list...
|
||||
contract Derived1 is Base(7) {
|
||||
constructor() public {}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
// or through a "modifier" of the derived constructor.
|
||||
contract Derived2 is Base {
|
||||
constructor(uint _y) Base(_y * _y) public {}
|
||||
constructor(uint _y) Base(_y * _y) {}
|
||||
}
|
||||
|
||||
One way is directly in the inheritance list (``is Base(7)``). The other is in
|
||||
@ -490,7 +502,7 @@ error "Linearization of inheritance graph impossible".
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract X {}
|
||||
contract A is X {}
|
||||
@ -511,14 +523,14 @@ One area where inheritance linearization is especially important and perhaps not
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract Base1 {
|
||||
constructor() public {}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
contract Base2 {
|
||||
constructor() public {}
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
// Constructors are executed in the following order:
|
||||
@ -526,7 +538,7 @@ One area where inheritance linearization is especially important and perhaps not
|
||||
// 2 - Base2
|
||||
// 3 - Derived1
|
||||
contract Derived1 is Base1, Base2 {
|
||||
constructor() public Base1() Base2() {}
|
||||
constructor() Base1() Base2() {}
|
||||
}
|
||||
|
||||
// Constructors are executed in the following order:
|
||||
@ -534,7 +546,7 @@ One area where inheritance linearization is especially important and perhaps not
|
||||
// 2 - Base1
|
||||
// 3 - Derived2
|
||||
contract Derived2 is Base2, Base1 {
|
||||
constructor() public Base2() Base1() {}
|
||||
constructor() Base2() Base1() {}
|
||||
}
|
||||
|
||||
// Constructors are still executed in the following order:
|
||||
@ -542,7 +554,7 @@ One area where inheritance linearization is especially important and perhaps not
|
||||
// 2 - Base1
|
||||
// 3 - Derived3
|
||||
contract Derived3 is Base2, Base1 {
|
||||
constructor() public Base1() Base2() {}
|
||||
constructor() Base1() Base2() {}
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,7 +23,7 @@ Interfaces are denoted by their own keyword:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.2 <0.7.0;
|
||||
pragma solidity >=0.6.2 <0.8.0;
|
||||
|
||||
interface Token {
|
||||
enum TokenType { Fungible, NonFungible }
|
||||
@ -44,7 +44,7 @@ inheritance.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.2 <0.7.0;
|
||||
pragma solidity >=0.6.2 <0.8.0;
|
||||
|
||||
interface ParentA {
|
||||
function test() external returns (uint256);
|
||||
|
@ -30,9 +30,8 @@ not possible to destroy a library.
|
||||
Libraries can be seen as implicit base contracts of the contracts that use them.
|
||||
They will not be explicitly visible in the inheritance hierarchy, but calls
|
||||
to library functions look just like calls to functions of explicit base
|
||||
contracts (``L.f()`` if ``L`` is the name of the library). Furthermore,
|
||||
``internal`` functions of libraries are visible in all contracts, just as
|
||||
if the library were a base contract. Of course, calls to internal functions
|
||||
contracts (using qualified access like ``L.f()``).
|
||||
Of course, calls to internal functions
|
||||
use the internal calling convention, which means that all internal types
|
||||
can be passed and types :ref:`stored in memory <data-location>` will be passed by reference and not copied.
|
||||
To realize this in the EVM, code of internal library functions
|
||||
@ -48,7 +47,7 @@ more advanced example to implement a set).
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
|
||||
// We define a new struct datatype that will be used to
|
||||
@ -127,7 +126,7 @@ custom types without the overhead of external function calls:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
struct bigint {
|
||||
uint[] limbs;
|
||||
@ -242,7 +241,7 @@ Its value can be obtained from Solidity using the ``.selector`` member as follow
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.14 <0.7.0;
|
||||
pragma solidity >=0.5.14 <0.8.0;
|
||||
|
||||
library L {
|
||||
function f(uint256) external {}
|
||||
|
@ -30,7 +30,7 @@ Let us rewrite the set example from the
|
||||
:ref:`libraries` in this way::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
|
||||
// This is the same code as before, just without comments
|
||||
@ -83,7 +83,7 @@ Let us rewrite the set example from the
|
||||
It is also possible to extend elementary types in that way::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
library Search {
|
||||
function indexOf(uint[] storage self, uint value)
|
||||
|
@ -55,7 +55,7 @@ return parameter list for functions.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function f(uint a) private pure returns (uint b) { return a + 1; }
|
||||
@ -70,7 +70,7 @@ In the following example, ``D``, can call ``c.getData()`` to retrieve the value
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract C {
|
||||
uint private data;
|
||||
@ -115,7 +115,7 @@ when they are declared.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract C {
|
||||
uint public data = 42;
|
||||
@ -136,7 +136,7 @@ it evaluates to a state variable. If it is accessed externally
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract C {
|
||||
uint public data;
|
||||
@ -156,7 +156,7 @@ to write a function, for example:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract arrayExample {
|
||||
// public state variable
|
||||
@ -183,7 +183,7 @@ The next example is more complex:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract Complex {
|
||||
struct Data {
|
||||
|
@ -443,7 +443,7 @@ or ``interface`` using the ``./test/cmdlineTests.sh`` script when you create a P
|
||||
ensure they work and pass tests before creating the PR.
|
||||
|
||||
Ensure that all code examples begin with a ``pragma`` version that spans the largest where the contract code is valid.
|
||||
For example ``pragma solidity >=0.4.0 <0.7.0;``.
|
||||
For example ``pragma solidity >=0.4.0 <0.8.0;``.
|
||||
|
||||
Running Documentation Tests
|
||||
---------------------------
|
||||
|
@ -42,7 +42,7 @@ Functions of the current contract can be called directly ("internally"), also re
|
||||
this nonsensical example::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function g(uint a) public pure returns (uint ret) { return a + f(); }
|
||||
@ -84,7 +84,7 @@ to the total balance of that contract:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.2 <0.7.0;
|
||||
pragma solidity >=0.6.2 <0.8.0;
|
||||
|
||||
contract InfoFeed {
|
||||
function info() public payable returns (uint ret) { return 42; }
|
||||
@ -125,9 +125,9 @@ throws an exception or goes out of gas.
|
||||
so your contract is not vulnerable to a reentrancy exploit.
|
||||
|
||||
.. note::
|
||||
Before Solidity 0.6.2, the recommended way to specify the value and gas
|
||||
was to use ``f.value(x).gas(g)()``. This is still possible but deprecated
|
||||
and will be removed with Solidity 0.7.0.
|
||||
Before Solidity 0.6.2, the recommended way to specify the value and gas was to
|
||||
use ``f.value(x).gas(g)()``. This was deprecated in Solidity 0.6.2 and is no
|
||||
longer possible since Solidity 0.7.0.
|
||||
|
||||
Named Calls and Anonymous Function Parameters
|
||||
---------------------------------------------
|
||||
@ -140,7 +140,7 @@ parameters from the function declaration, but can be in arbitrary order.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract C {
|
||||
mapping(uint => uint) data;
|
||||
@ -164,7 +164,7 @@ Those parameters will still be present on the stack, but they are inaccessible.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
contract C {
|
||||
// omitted name for parameter
|
||||
@ -188,11 +188,11 @@ is compiled so recursive creation-dependencies are not possible.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.2 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract D {
|
||||
uint public x;
|
||||
constructor(uint a) public payable {
|
||||
constructor(uint a) payable {
|
||||
x = a;
|
||||
}
|
||||
}
|
||||
@ -244,11 +244,11 @@ which only need to be created if there is a dispute.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.2 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract D {
|
||||
uint public x;
|
||||
constructor(uint a) public {
|
||||
constructor(uint a) {
|
||||
x = a;
|
||||
}
|
||||
}
|
||||
@ -314,7 +314,7 @@ groupings of expressions.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
contract C {
|
||||
uint index;
|
||||
@ -360,7 +360,7 @@ because only a reference and not a copy is passed.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
contract C {
|
||||
uint[20] x;
|
||||
@ -419,7 +419,7 @@ the two variables have the same name but disjoint scopes.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
contract C {
|
||||
function minimalScoping() pure public {
|
||||
{
|
||||
@ -441,7 +441,7 @@ In any case, you will get a warning about the outer variable being shadowed.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
// This will report a warning
|
||||
contract C {
|
||||
function f() pure public returns (uint) {
|
||||
@ -463,7 +463,7 @@ In any case, you will get a warning about the outer variable being shadowed.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
// This will not compile
|
||||
contract C {
|
||||
function f() pure public returns (uint) {
|
||||
@ -552,7 +552,7 @@ and ``assert`` for internal error checking.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
contract Sharer {
|
||||
function sendHalf(address payable addr) public payable returns (uint balance) {
|
||||
@ -597,7 +597,7 @@ The following example shows how to use an error string together with ``revert``
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
contract VendingMachine {
|
||||
function buy(uint amount) public payable {
|
||||
@ -641,7 +641,7 @@ A failure in an external call can be caught using a try/catch statement, as foll
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
interface DataFeed { function getData(address token) external returns (uint value); }
|
||||
|
||||
@ -730,4 +730,4 @@ in scope in the block that follows.
|
||||
out-of-gas situation and not a deliberate error condition:
|
||||
The caller always retains 63/64th of the gas in a call and thus
|
||||
even if the called contract goes out of gas, the caller still
|
||||
has some gas left.
|
||||
has some gas left.
|
||||
|
@ -25,7 +25,7 @@ to receive their money - contracts cannot activate themselves.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract SimpleAuction {
|
||||
// Parameters of the auction. Times are either
|
||||
@ -60,9 +60,9 @@ to receive their money - contracts cannot activate themselves.
|
||||
constructor(
|
||||
uint _biddingTime,
|
||||
address payable _beneficiary
|
||||
) public {
|
||||
) {
|
||||
beneficiary = _beneficiary;
|
||||
auctionEndTime = now + _biddingTime;
|
||||
auctionEndTime = block.timestamp + _biddingTime;
|
||||
}
|
||||
|
||||
/// Bid on the auction with the value sent
|
||||
@ -79,7 +79,7 @@ to receive their money - contracts cannot activate themselves.
|
||||
// Revert the call if the bidding
|
||||
// period is over.
|
||||
require(
|
||||
now <= auctionEndTime,
|
||||
block.timestamp <= auctionEndTime,
|
||||
"Auction already ended."
|
||||
);
|
||||
|
||||
@ -141,7 +141,7 @@ to receive their money - contracts cannot activate themselves.
|
||||
// external contracts.
|
||||
|
||||
// 1. Conditions
|
||||
require(now >= auctionEndTime, "Auction not yet ended.");
|
||||
require(block.timestamp >= auctionEndTime, "Auction not yet ended.");
|
||||
require(!ended, "auctionEnd has already been called.");
|
||||
|
||||
// 2. Effects
|
||||
@ -186,7 +186,7 @@ invalid bids.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract BlindAuction {
|
||||
struct Bid {
|
||||
@ -213,16 +213,16 @@ invalid bids.
|
||||
/// functions. `onlyBefore` is applied to `bid` below:
|
||||
/// The new function body is the modifier's body where
|
||||
/// `_` is replaced by the old function body.
|
||||
modifier onlyBefore(uint _time) { require(now < _time); _; }
|
||||
modifier onlyAfter(uint _time) { require(now > _time); _; }
|
||||
modifier onlyBefore(uint _time) { require(block.timestamp < _time); _; }
|
||||
modifier onlyAfter(uint _time) { require(block.timestamp > _time); _; }
|
||||
|
||||
constructor(
|
||||
uint _biddingTime,
|
||||
uint _revealTime,
|
||||
address payable _beneficiary
|
||||
) public {
|
||||
) {
|
||||
beneficiary = _beneficiary;
|
||||
biddingEnd = now + _biddingTime;
|
||||
biddingEnd = block.timestamp + _biddingTime;
|
||||
revealEnd = biddingEnd + _revealTime;
|
||||
}
|
||||
|
||||
@ -328,4 +328,4 @@ invalid bids.
|
||||
highestBidder = bidder;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,14 +143,14 @@ The full contract
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.24 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract ReceiverPays {
|
||||
address owner = msg.sender;
|
||||
|
||||
mapping(uint256 => bool) usedNonces;
|
||||
|
||||
constructor() public payable {}
|
||||
constructor() payable {}
|
||||
|
||||
function claimPayment(uint256 amount, uint256 nonce, bytes memory signature) public {
|
||||
require(!usedNonces[nonce]);
|
||||
@ -340,7 +340,7 @@ The full contract
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract SimplePaymentChannel {
|
||||
address payable public sender; // The account sending payments.
|
||||
@ -348,12 +348,11 @@ The full contract
|
||||
uint256 public expiration; // Timeout in case the recipient never closes.
|
||||
|
||||
constructor (address payable _recipient, uint256 duration)
|
||||
public
|
||||
payable
|
||||
{
|
||||
sender = msg.sender;
|
||||
recipient = _recipient;
|
||||
expiration = now + duration;
|
||||
expiration = block.timestamp + duration;
|
||||
}
|
||||
|
||||
/// the recipient can close the channel at any time by presenting a
|
||||
@ -378,7 +377,7 @@ The full contract
|
||||
/// if the timeout is reached without the recipient closing the channel,
|
||||
/// then the Ether is released back to the sender.
|
||||
function claimTimeout() public {
|
||||
require(now >= expiration);
|
||||
require(block.timestamp >= expiration);
|
||||
selfdestruct(sender);
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,7 @@ and the sum of all balances is an invariant across the lifetime of the contract.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
library Balances {
|
||||
function move(mapping(address => uint256) storage balances, address from, address to, uint amount) internal {
|
||||
|
@ -26,7 +26,7 @@ you can use state machine-like constructs inside a contract.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract Purchase {
|
||||
uint public value;
|
||||
@ -74,7 +74,7 @@ you can use state machine-like constructs inside a contract.
|
||||
// Ensure that `msg.value` is an even number.
|
||||
// Division will truncate if it is an odd number.
|
||||
// Check via multiplication that it wasn't an odd number.
|
||||
constructor() public payable {
|
||||
constructor() payable {
|
||||
seller = msg.sender;
|
||||
value = msg.value / 2;
|
||||
require((2 * value) == msg.value, "Value has to be even.");
|
||||
|
@ -33,7 +33,7 @@ of votes.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
/// @title Voting with delegation.
|
||||
contract Ballot {
|
||||
@ -63,7 +63,7 @@ of votes.
|
||||
Proposal[] public proposals;
|
||||
|
||||
/// Create a new ballot to choose one of `proposalNames`.
|
||||
constructor(bytes32[] memory proposalNames) public {
|
||||
constructor(bytes32[] memory proposalNames) {
|
||||
chairperson = msg.sender;
|
||||
voters[chairperson].weight = 1;
|
||||
|
||||
|
@ -127,6 +127,7 @@ Contents
|
||||
|
||||
050-breaking-changes.rst
|
||||
060-breaking-changes.rst
|
||||
070-breaking-changes.rst
|
||||
natspec-format.rst
|
||||
security-considerations.rst
|
||||
resources.rst
|
||||
|
@ -72,7 +72,7 @@ the position of ``data[4][9].b`` is at ``keccak256(uint256(9) . keccak256(uint25
|
||||
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
|
||||
contract C {
|
||||
@ -173,7 +173,7 @@ value and reference types, types that are encoded packed, and nested types.
|
||||
.. code::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
contract A {
|
||||
struct S {
|
||||
uint128 a;
|
||||
|
@ -18,7 +18,7 @@ Storage Example
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract SimpleStorage {
|
||||
uint storedData;
|
||||
@ -83,7 +83,7 @@ registering with a username and password, all you need is an Ethereum keypair.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.5.99 <0.8.0;
|
||||
|
||||
contract Coin {
|
||||
// The keyword "public" makes variables
|
||||
@ -97,7 +97,7 @@ registering with a username and password, all you need is an Ethereum keypair.
|
||||
|
||||
// Constructor code is only run when the contract
|
||||
// is created
|
||||
constructor() public {
|
||||
constructor() {
|
||||
minter = msg.sender;
|
||||
}
|
||||
|
||||
@ -186,7 +186,7 @@ and any user interface calls the automatically generated ``balances`` function f
|
||||
|
||||
.. index:: coin
|
||||
|
||||
The :ref:`constructor<constructor>` is a special function run during the creation of the contract and
|
||||
The :ref:`constructor<constructor>` is a special function that is executed during the creation of the contract and
|
||||
cannot be called afterwards. In this case, it permanently stores the address of the person creating the
|
||||
contract. The ``msg`` variable (together with ``tx`` and ``block``) is a
|
||||
:ref:`special global variable <special-variables-functions>` that
|
||||
|
@ -317,7 +317,7 @@ for the two function parameters and two return variables.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.21 <0.7.0;
|
||||
pragma solidity >=0.4.21 <0.8.0;
|
||||
|
||||
/** @title Shape calculator. */
|
||||
contract ShapeCalculator {
|
||||
|
@ -49,7 +49,7 @@ The following example shows a contract and a function using all available tags.
|
||||
.. code:: solidity
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >0.6.10 <0.7.0;
|
||||
pragma solidity >0.6.10 <0.8.0;
|
||||
|
||||
/// @title A simulator for trees
|
||||
/// @author Larry A. Gardner
|
||||
|
@ -59,7 +59,7 @@ complete contract):
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
|
||||
contract Fund {
|
||||
@ -83,7 +83,7 @@ as it uses ``call`` which forwards all remaining gas by default:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.2 <0.7.0;
|
||||
pragma solidity >=0.6.2 <0.8.0;
|
||||
|
||||
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
|
||||
contract Fund {
|
||||
@ -103,7 +103,7 @@ outlined further below:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.11 <0.7.0;
|
||||
pragma solidity >=0.4.11 <0.8.0;
|
||||
|
||||
contract Fund {
|
||||
/// @dev Mapping of ether shares of the contract.
|
||||
@ -201,13 +201,13 @@ Never use tx.origin for authorization. Let's say you have a wallet contract like
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
|
||||
contract TxUserWallet {
|
||||
address owner;
|
||||
|
||||
constructor() public {
|
||||
constructor() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
@ -222,7 +222,7 @@ Now someone tricks you into sending Ether to the address of this attack wallet:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
interface TxUserWallet {
|
||||
function transferTo(address payable dest, uint amount) external;
|
||||
@ -231,7 +231,7 @@ Now someone tricks you into sending Ether to the address of this attack wallet:
|
||||
contract TxAttackWallet {
|
||||
address payable owner;
|
||||
|
||||
constructor() public {
|
||||
constructor() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
@ -283,7 +283,7 @@ field of a ``struct`` that is the base type of a dynamic storage array. The
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract Map {
|
||||
mapping (uint => uint)[] array;
|
||||
|
@ -27,7 +27,7 @@ storage.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract SimpleStorage {
|
||||
uint storedData; // State variable
|
||||
@ -48,7 +48,7 @@ Functions are the executable units of code within a contract.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract SimpleAuction {
|
||||
function bid() public payable { // Function
|
||||
@ -77,7 +77,7 @@ Like functions, modifiers can be :ref:`overridden <modifier-overriding>`.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
contract Purchase {
|
||||
address public seller;
|
||||
@ -105,7 +105,7 @@ Events are convenience interfaces with the EVM logging facilities.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.21 <0.7.0;
|
||||
pragma solidity >=0.4.21 <0.8.0;
|
||||
|
||||
contract SimpleAuction {
|
||||
event HighestBidIncreased(address bidder, uint amount); // Event
|
||||
@ -130,7 +130,7 @@ Structs are custom defined types that can group several variables (see
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract Ballot {
|
||||
struct Voter { // Struct
|
||||
@ -152,7 +152,7 @@ Enums can be used to create custom types with a finite set of 'constant values'
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract Purchase {
|
||||
enum State { Created, Locked, Inactive } // Enum
|
||||
|
@ -56,7 +56,7 @@ Surround top level declarations in solidity source with two blank lines.
|
||||
Yes::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract A {
|
||||
// ...
|
||||
@ -75,7 +75,7 @@ Yes::
|
||||
No::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract A {
|
||||
// ...
|
||||
@ -95,7 +95,7 @@ Blank lines may be omitted between groups of related one-liners (such as stub fu
|
||||
Yes::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
abstract contract A {
|
||||
function spam() public virtual pure;
|
||||
@ -116,7 +116,7 @@ Yes::
|
||||
No::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
abstract contract A {
|
||||
function spam() virtual pure public;
|
||||
@ -251,7 +251,7 @@ Import statements should always be placed at the top of the file.
|
||||
Yes::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
import "./Owned.sol";
|
||||
|
||||
@ -266,7 +266,7 @@ Yes::
|
||||
No::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract A {
|
||||
// ...
|
||||
@ -300,10 +300,10 @@ Within a grouping, place the ``view`` and ``pure`` functions last.
|
||||
Yes::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract A {
|
||||
constructor() public {
|
||||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
@ -337,7 +337,7 @@ Yes::
|
||||
No::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity ^0.6.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract A {
|
||||
|
||||
@ -357,7 +357,7 @@ No::
|
||||
// Public functions
|
||||
// ...
|
||||
|
||||
constructor() public {
|
||||
constructor() {
|
||||
// ...
|
||||
}
|
||||
|
||||
@ -445,7 +445,7 @@ should:
|
||||
Yes::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract Coin {
|
||||
struct Bank {
|
||||
@ -457,7 +457,7 @@ Yes::
|
||||
No::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract Coin
|
||||
{
|
||||
@ -758,19 +758,19 @@ manner as modifiers if the function declaration is long or hard to read.
|
||||
Yes::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
// Base contracts just to make this compile
|
||||
contract B {
|
||||
constructor(uint) public {
|
||||
constructor(uint) {
|
||||
}
|
||||
}
|
||||
contract C {
|
||||
constructor(uint, uint) public {
|
||||
constructor(uint, uint) {
|
||||
}
|
||||
}
|
||||
contract D {
|
||||
constructor(uint) public {
|
||||
constructor(uint) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -781,7 +781,6 @@ Yes::
|
||||
B(param1)
|
||||
C(param2, param3)
|
||||
D(param4)
|
||||
public
|
||||
{
|
||||
// do something with param5
|
||||
x = param5;
|
||||
@ -791,24 +790,24 @@ Yes::
|
||||
No::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
|
||||
// Base contracts just to make this compile
|
||||
contract B {
|
||||
constructor(uint) public {
|
||||
constructor(uint) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract C {
|
||||
constructor(uint, uint) public {
|
||||
constructor(uint, uint) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
contract D {
|
||||
constructor(uint) public {
|
||||
constructor(uint) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -819,8 +818,7 @@ No::
|
||||
constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
|
||||
B(param1)
|
||||
C(param2, param3)
|
||||
D(param4)
|
||||
public {
|
||||
D(param4) {
|
||||
x = param5;
|
||||
}
|
||||
}
|
||||
@ -832,8 +830,7 @@ No::
|
||||
constructor(uint param1, uint param2, uint param3, uint param4, uint param5)
|
||||
B(param1)
|
||||
C(param2, param3)
|
||||
D(param4)
|
||||
public {
|
||||
D(param4) {
|
||||
x = param5;
|
||||
}
|
||||
}
|
||||
@ -1015,14 +1012,14 @@ As shown in the example below, if the contract name is ``Congress`` and the libr
|
||||
Yes::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
|
||||
// Owned.sol
|
||||
contract Owned {
|
||||
address public owner;
|
||||
|
||||
constructor() public {
|
||||
constructor() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
@ -1039,7 +1036,7 @@ Yes::
|
||||
and in ``Congress.sol``::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
import "./Owned.sol";
|
||||
|
||||
@ -1051,14 +1048,14 @@ and in ``Congress.sol``::
|
||||
No::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
|
||||
// owned.sol
|
||||
contract owned {
|
||||
address public owner;
|
||||
|
||||
constructor() public {
|
||||
constructor() {
|
||||
owner = msg.sender;
|
||||
}
|
||||
|
||||
@ -1096,7 +1093,7 @@ Events should be named using the CapWords style. Examples: ``Deposit``, ``Transf
|
||||
Function Names
|
||||
==============
|
||||
|
||||
Functions other than constructors should use mixedCase. Examples: ``getBalance``, ``transfer``, ``verifyOwner``, ``addMember``, ``changeOwner``.
|
||||
Functions should use mixedCase. Examples: ``getBalance``, ``transfer``, ``verifyOwner``, ``addMember``, ``changeOwner``.
|
||||
|
||||
|
||||
Function Argument Names
|
||||
@ -1156,7 +1153,7 @@ For example, the contract from `a simple smart contract <simple-smart-contract>`
|
||||
added looks like the one below::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
|
||||
/// @author The Solidity Team
|
||||
|
@ -26,6 +26,7 @@ are allowed for state variables, as storage reference types
|
||||
in functions, or as parameters for library functions.
|
||||
They cannot be used as parameters or return parameters
|
||||
of contract functions that are publicly visible.
|
||||
These restrictions are also true for arrays and structs that contain mappings.
|
||||
|
||||
You can mark state variables of mapping type as ``public`` and Solidity creates a
|
||||
:ref:`getter <visibility-and-getters>` for you. The ``_KeyType`` becomes a parameter for the getter.
|
||||
@ -42,7 +43,7 @@ contract that returns the value at the specified address.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract MappingExample {
|
||||
mapping(address => uint) public balances;
|
||||
@ -68,7 +69,7 @@ The example below uses ``_allowances`` to record the amount someone else is allo
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
contract MappingExample {
|
||||
|
||||
@ -123,7 +124,7 @@ the ``sum`` function iterates over to sum all the values.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
struct IndexValue { uint keyIndex; uint value; }
|
||||
struct KeyFlag { uint key; bool deleted; }
|
||||
|
@ -43,7 +43,7 @@ value it referred to previously.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract DeleteExample {
|
||||
uint data;
|
||||
|
@ -63,7 +63,7 @@ Data locations are not only relevant for persistency of data, but also for the s
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.5.0 <0.7.0;
|
||||
pragma solidity >=0.5.0 <0.8.0;
|
||||
|
||||
contract C {
|
||||
// The data location of x is storage.
|
||||
@ -174,7 +174,7 @@ or create a new memory array and copy every element.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function f(uint len) public pure {
|
||||
@ -206,7 +206,7 @@ the first element to ``uint``.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function f() public pure {
|
||||
@ -223,7 +223,7 @@ memory arrays, i.e. the following is not possible:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
// This will not compile.
|
||||
contract C {
|
||||
@ -243,7 +243,7 @@ individual elements:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.0 <0.7.0;
|
||||
pragma solidity >=0.4.0 <0.8.0;
|
||||
|
||||
contract C {
|
||||
function f() public pure {
|
||||
@ -301,7 +301,7 @@ Array Members
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
contract ArrayContract {
|
||||
uint[2**20] m_aLotOfIntegers;
|
||||
@ -434,13 +434,13 @@ Array slices are useful to ABI-decode secondary data passed in function paramete
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
|
||||
contract Proxy {
|
||||
/// @dev Address of the client contract managed by proxy i.e., this contract
|
||||
address client;
|
||||
|
||||
constructor(address _client) public {
|
||||
constructor(address _client) {
|
||||
client = _client;
|
||||
}
|
||||
|
||||
@ -478,7 +478,7 @@ shown in the following example:
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
pragma solidity >=0.6.0 <0.8.0;
|
||||
|
||||
// Defines a new type with two fields.
|
||||
// Declaring a struct outside of a contract allows
|
||||
@ -505,12 +505,11 @@ shown in the following example:
|
||||
|
||||
function newCampaign(address payable beneficiary, uint goal) public returns (uint campaignID) {
|
||||
campaignID = numCampaigns++; // campaignID is return variable
|
||||
// Creates new struct in memory and copies it to storage.
|
||||
// We leave out the mapping type, because it is not valid in memory.
|
||||
// If structs are copied (even from storage to storage),
|
||||
// types that are not valid outside of storage (ex. mappings and array of mappings)
|
||||
// are always omitted, because they cannot be enumerated.
|
||||
campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0);
|
||||
// We cannot use "campaigns[campaignID] = Campaign(beneficiary, goal, 0, 0)"
|
||||
// because the RHS creates a memory-struct "Campaign" that contains a mapping.
|
||||
Campaign storage c = campaigns[campaignID];
|
||||
c.beneficiary = beneficiary;
|
||||
c.fundingGoal = goal;
|
||||
}
|
||||
|
||||
function contribute(uint campaignID) public payable {
|
||||
|
@ -64,11 +64,11 @@ Shifts
|
||||
^^^^^^
|
||||
|
||||
The result of a shift operation has the type of the left operand, truncating the result to match the type.
|
||||
Right operand must be unsigned type. Trying to shift by signed type will produce a compilation error.
|
||||
|
||||
- For positive and negative ``x`` values, ``x << y`` is equivalent to ``x * 2**y``.
|
||||
- For positive ``x`` values, ``x >> y`` is equivalent to ``x / 2**y``.
|
||||
- For negative ``x`` values, ``x >> y`` is equivalent to ``(x + 1) / 2**y - 1`` (which is the same as dividing ``x`` by ``2**y`` while rounding down towards negative infinity).
|
||||
- In all cases, shifting by a negative ``y`` throws a runtime exception.
|
||||
|
||||
.. warning::
|
||||
Before version ``0.5.0`` a right shift ``x >> y`` for negative ``x`` was equivalent to ``x / 2**y``,
|
||||
@ -370,9 +370,9 @@ Operators:
|
||||
* Shift operators: ``<<`` (left shift), ``>>`` (right shift)
|
||||
* Index access: If ``x`` is of type ``bytesI``, then ``x[k]`` for ``0 <= k < I`` returns the ``k`` th byte (read-only).
|
||||
|
||||
The shifting operator works with any integer type as right operand (but
|
||||
The shifting operator works with unsigned integer type as right operand (but
|
||||
returns the type of the left operand), which denotes the number of bits to shift by.
|
||||
Shifting by a negative amount causes a runtime exception.
|
||||
Shifting by a signed type will produce a compilation error.
|
||||
|
||||
Members:
|
||||
|
||||
@ -444,6 +444,11 @@ long as the operands are integers. If any of the two is fractional, bit operatio
|
||||
and exponentiation is disallowed if the exponent is fractional (because that might result in
|
||||
a non-rational number).
|
||||
|
||||
Shifts and exponentiation with literal numbers as left (or base) operand and integer types
|
||||
as the right (exponent) operand are always performed
|
||||
in the ``uint256`` (for non-negative literals) or ``int256`` (for a negative literals) type,
|
||||
regardless of the type of the right (exponent) operand.
|
||||
|
||||
.. warning::
|
||||
Division on integer literals used to truncate in Solidity prior to version 0.4.0, but it now converts into a rational number, i.e. ``5 / 2`` is not equal to ``2``, but to ``2.5``.
|
||||
|
||||
@ -544,7 +549,7 @@ subsequent unsigned integer values starting from ``0``.
|
||||
::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
contract test {
|
||||
enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill }
|
||||
@ -645,18 +650,19 @@ External (or public) functions have the following members:
|
||||
|
||||
* ``.address`` returns the address of the contract of the function.
|
||||
* ``.selector`` returns the :ref:`ABI function selector <abi_function_selector>`
|
||||
* ``.gas(uint)`` returns a callable function object which, when called, will send
|
||||
the specified amount of gas to the target function. Deprecated - use ``{gas: ...}`` instead.
|
||||
See :ref:`External Function Calls <external-function-calls>` for more information.
|
||||
* ``.value(uint)`` returns a callable function object which, when called, will
|
||||
send the specified amount of wei to the target function. Deprecated - use ``{value: ...}`` instead.
|
||||
See :ref:`External Function Calls <external-function-calls>` for more information.
|
||||
|
||||
.. note::
|
||||
External (or public) functions used to have the additional members
|
||||
``.gas(uint)`` and ``.value(uint)``. These were deprecated in Solidity 0.6.2
|
||||
and removed in Solidity 0.7.0. Instead use ``{gas: ...}`` and ``{value: ...}``
|
||||
to specify the amount of gas or the amount of wei sent to a function,
|
||||
respectively. See :ref:`External Function Calls <external-function-calls>` for
|
||||
more information.
|
||||
|
||||
Example that shows how to use the members::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
// This will report a warning
|
||||
pragma solidity >=0.6.4 <0.8.0;
|
||||
|
||||
contract Example {
|
||||
function f() public payable returns (bytes4) {
|
||||
@ -665,16 +671,14 @@ Example that shows how to use the members::
|
||||
}
|
||||
|
||||
function g() public {
|
||||
this.f.gas(10).value(800)();
|
||||
// New syntax:
|
||||
// this.f{gas: 10, value: 800}()
|
||||
this.f{gas: 10, value: 800}();
|
||||
}
|
||||
}
|
||||
|
||||
Example that shows how to use internal function types::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.16 <0.7.0;
|
||||
pragma solidity >=0.4.16 <0.8.0;
|
||||
|
||||
library ArrayUtils {
|
||||
// internal functions can be used in internal library functions because
|
||||
@ -732,7 +736,7 @@ Example that shows how to use internal function types::
|
||||
Another example that uses external function types::
|
||||
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.4.22 <0.7.0;
|
||||
pragma solidity >=0.4.22 <0.8.0;
|
||||
|
||||
|
||||
contract Oracle {
|
||||
|
@ -2,23 +2,23 @@
|
||||
Units and Globally Available Variables
|
||||
**************************************
|
||||
|
||||
.. index:: wei, finney, szabo, ether
|
||||
.. index:: wei, finney, szabo, gwei, ether
|
||||
|
||||
Ether Units
|
||||
===========
|
||||
|
||||
A literal number can take a suffix of ``wei``, ``gwei``, ``finney``, ``szabo`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
|
||||
A literal number can take a suffix of ``wei``, ``gwei`` or ``ether`` to specify a subdenomination of Ether, where Ether numbers without a postfix are assumed to be Wei.
|
||||
|
||||
::
|
||||
|
||||
assert(1 wei == 1);
|
||||
assert(1 gwei == 1e9);
|
||||
assert(1 szabo == 1e12);
|
||||
assert(1 finney == 1e15);
|
||||
assert(1 ether == 1e18);
|
||||
|
||||
The only effect of the subdenomination suffix is a multiplication by a power of ten.
|
||||
|
||||
.. note::
|
||||
The denominations ``finney`` and ``szabo`` have been removed in version 0.7.0.
|
||||
|
||||
.. index:: time, seconds, minutes, hours, days, weeks, years
|
||||
|
||||
@ -48,7 +48,7 @@ These suffixes cannot be applied to variables. For example, if you want to
|
||||
interpret a function parameter in days, you can in the following way::
|
||||
|
||||
function f(uint start, uint daysAfter) public {
|
||||
if (now >= start + daysAfter * 1 days) {
|
||||
if (block.timestamp >= start + daysAfter * 1 days) {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
@ -62,7 +62,7 @@ There are special variables and functions which always exist in the global
|
||||
namespace and are mainly used to provide information about the blockchain
|
||||
or are general-use utility functions.
|
||||
|
||||
.. index:: abi, block, coinbase, difficulty, encode, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, now, gas price, origin
|
||||
.. index:: abi, block, coinbase, difficulty, encode, number, block;number, timestamp, block;timestamp, msg, data, gas, sender, value, gas price, origin
|
||||
|
||||
|
||||
Block and Transaction Properties
|
||||
@ -79,7 +79,6 @@ Block and Transaction Properties
|
||||
- ``msg.sender`` (``address payable``): sender of the message (current call)
|
||||
- ``msg.sig`` (``bytes4``): first four bytes of the calldata (i.e. function identifier)
|
||||
- ``msg.value`` (``uint``): number of wei sent with the message
|
||||
- ``now`` (``uint``): current block timestamp (alias for ``block.timestamp``)
|
||||
- ``tx.gasprice`` (``uint``): gas price of the transaction
|
||||
- ``tx.origin`` (``address payable``): sender of the transaction (full call chain)
|
||||
|
||||
@ -89,7 +88,7 @@ Block and Transaction Properties
|
||||
This includes calls to library functions.
|
||||
|
||||
.. note::
|
||||
Do not rely on ``block.timestamp``, ``now`` and ``blockhash`` as a source of randomness,
|
||||
Do not rely on ``block.timestamp`` or ``blockhash`` as a source of randomness,
|
||||
unless you know what you are doing.
|
||||
|
||||
Both the timestamp and the block hash can be influenced by miners to some degree.
|
||||
@ -113,6 +112,9 @@ Block and Transaction Properties
|
||||
The function ``gasleft`` was previously known as ``msg.gas``, which was deprecated in
|
||||
version 0.4.21 and removed in version 0.5.0.
|
||||
|
||||
.. note::
|
||||
In version 0.7.0, the alias ``now`` (for ``block.timestamp``) was removed.
|
||||
|
||||
.. index:: abi, encoding, packed
|
||||
|
||||
ABI Encoding and Decoding Functions
|
||||
|
@ -566,27 +566,40 @@ the latest version of the compiler.
|
||||
Available upgrade modules
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| Module | Version | Description |
|
||||
+=================+=========+==================================================+
|
||||
| ``constructor`` | 0.5.0 | Constructors must now be defined using the |
|
||||
| | | ``constructor`` keyword. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``visibility`` | 0.5.0 | Explicit function visibility is now mandatory, |
|
||||
| | | defaults to ``public``. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``abstract`` | 0.6.0 | The keyword ``abstract`` has to be used if a |
|
||||
| | | contract does not implement all its functions. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``virtual`` | 0.6.0 | Functions without implementation outside an |
|
||||
| | | interface have to be marked ``virtual``. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
| ``override`` | 0.6.0 | When overriding a function or modifier, the new |
|
||||
| | | keyword ``override`` must be used. |
|
||||
+-----------------+---------+--------------------------------------------------+
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| Module | Version | Description |
|
||||
+============================+=========+==================================================+
|
||||
| ``constructor`` | 0.5.0 | Constructors must now be defined using the |
|
||||
| | | ``constructor`` keyword. |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| ``visibility`` | 0.5.0 | Explicit function visibility is now mandatory, |
|
||||
| | | defaults to ``public``. |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| ``abstract`` | 0.6.0 | The keyword ``abstract`` has to be used if a |
|
||||
| | | contract does not implement all its functions. |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| ``virtual`` | 0.6.0 | Functions without implementation outside an |
|
||||
| | | interface have to be marked ``virtual``. |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| ``override`` | 0.6.0 | When overriding a function or modifier, the new |
|
||||
| | | keyword ``override`` must be used. |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| ``dotsyntax`` | 0.7.0 | The following syntax is deprecated: |
|
||||
| | | ``f.gas(...)()``, ``f.value(...)()`` and |
|
||||
| | | ``(new C).value(...)()``. Replace these calls by |
|
||||
| | | ``f{gas: ..., value: ...}()`` and |
|
||||
| | | ``(new C){value: ...}()``. |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| ``now`` | 0.7.0 | The ``now`` keyword is deprecated. Use |
|
||||
| | | ``block.timestamp`` instead. |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
| ``constructor-visibility`` | 0.7.0 | Removes visibility of constructors. |
|
||||
| | | |
|
||||
+----------------------------+---------+--------------------------------------------------+
|
||||
|
||||
Please read :doc:`0.5.0 release notes <050-breaking-changes>` and
|
||||
:doc:`0.6.0 release notes <060-breaking-changes>` for further details.
|
||||
Please read :doc:`0.5.0 release notes <050-breaking-changes>`,
|
||||
:doc:`0.6.0 release notes <060-breaking-changes>` and
|
||||
:doc:`0.7.0 release notes <070-breaking-changes>` for further details.
|
||||
|
||||
Synopsis
|
||||
~~~~~~~~
|
||||
@ -622,115 +635,88 @@ If you found a bug or if you have a feature request, please
|
||||
Example
|
||||
~~~~~~~
|
||||
|
||||
Assume you have the following contracts you want to update declared in ``Source.sol``:
|
||||
Assume that you have the following contract in ``Source.sol``:
|
||||
|
||||
.. code-block:: none
|
||||
.. code-block:: solidity
|
||||
|
||||
// This will not compile after 0.5.0
|
||||
pragma solidity >=0.6.0 <0.6.4;
|
||||
// This will not compile after 0.7.0
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >0.4.23 <0.5.0;
|
||||
|
||||
contract Updateable {
|
||||
function run() public view returns (bool);
|
||||
function update() public;
|
||||
contract C {
|
||||
// FIXME: remove constructor visibility and make the contract abstract
|
||||
constructor() internal {}
|
||||
}
|
||||
|
||||
contract Upgradable {
|
||||
function run() public view returns (bool);
|
||||
function upgrade();
|
||||
contract D {
|
||||
uint time;
|
||||
|
||||
function f() public payable {
|
||||
// FIXME: change now to block.timestamp
|
||||
time = now;
|
||||
}
|
||||
}
|
||||
|
||||
contract Source is Updateable, Upgradable {
|
||||
function Source() public {}
|
||||
contract E {
|
||||
D d;
|
||||
|
||||
function run()
|
||||
public
|
||||
view
|
||||
returns (bool) {}
|
||||
// FIXME: remove constructor visibility
|
||||
constructor() public {}
|
||||
|
||||
function update() {}
|
||||
function upgrade() {}
|
||||
function g() public {
|
||||
// FIXME: change .value(5) => {value: 5}
|
||||
d.f.value(5)();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Required changes
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
To bring the contracts up to date with the current Solidity version, the
|
||||
following upgrade modules have to be executed: ``constructor``,
|
||||
``visibility``, ``abstract``, ``override`` and ``virtual``. Please read the
|
||||
documentation on :ref:`available modules <upgrade-modules>` for further details.
|
||||
The above contract will not compile starting from 0.7.0. To bring the contract up to date with the
|
||||
current Solidity version, the following upgrade modules have to be executed:
|
||||
``constructor-visibility``, ``now`` and ``dotsyntax``. Please read the documentation on
|
||||
:ref:`available modules <upgrade-modules>` for further details.
|
||||
|
||||
|
||||
Running the upgrade
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In this example, all modules needed to upgrade the contracts above,
|
||||
are available and all of them are activated by default. Therefore you
|
||||
do not need to specify the ``--modules`` option.
|
||||
It is recommended to explicitly specify the upgrade modules by using ``--modules`` argument.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ solidity-upgrade Source.sol --dry-run
|
||||
$ solidity-upgrade --modules constructor-visibility,now,dotsyntax Source.sol
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Running analysis (and upgrade) on given source files.
|
||||
..............
|
||||
|
||||
After upgrade:
|
||||
|
||||
Found 0 errors.
|
||||
Found 0 upgrades.
|
||||
|
||||
The above performs a dry-ran upgrade on the given file and logs statistics after all.
|
||||
In this case, the upgrade was successful and no further adjustments are needed.
|
||||
|
||||
Finally, you can run the upgrade and also write to the source file.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
$ solidity-upgrade Source.sol
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
Running analysis (and upgrade) on given source files.
|
||||
..............
|
||||
|
||||
After upgrade:
|
||||
|
||||
Found 0 errors.
|
||||
Found 0 upgrades.
|
||||
|
||||
|
||||
Review changes
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
The command above applies all changes as shown below. Please review them carefully.
|
||||
The command above applies all changes as shown below. Please review them carefully (the pragmas will
|
||||
have to be updated manually.)
|
||||
|
||||
.. code-block:: solidity
|
||||
|
||||
pragma solidity >0.6.99 <0.8.0;
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.6.0 <0.7.0;
|
||||
|
||||
abstract contract Updateable {
|
||||
function run() public view virtual returns (bool);
|
||||
function update() public virtual;
|
||||
abstract contract C {
|
||||
// FIXME: remove constructor visibility and make the contract abstract
|
||||
constructor() {}
|
||||
}
|
||||
|
||||
abstract contract Upgradable {
|
||||
function run() public view virtual returns (bool);
|
||||
function upgrade() public virtual;
|
||||
contract D {
|
||||
uint time;
|
||||
|
||||
function f() public payable {
|
||||
// FIXME: change now to block.timestamp
|
||||
time = block.timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
contract Source is Updateable, Upgradable {
|
||||
constructor() public {}
|
||||
contract E {
|
||||
D d;
|
||||
|
||||
function run()
|
||||
public
|
||||
view
|
||||
override(Updateable,Upgradable)
|
||||
returns (bool) {}
|
||||
// FIXME: remove constructor visibility
|
||||
constructor() {}
|
||||
|
||||
function update() public override {}
|
||||
function upgrade() public override {}
|
||||
function g() public {
|
||||
// FIXME: change .value(5) => {value: 5}
|
||||
d.f{value: 5}();
|
||||
}
|
||||
}
|
||||
|
@ -189,15 +189,13 @@ namespace solidity::langutil
|
||||
K(Throw, "throw", 0) \
|
||||
K(Type, "type", 0) \
|
||||
K(Using, "using", 0) \
|
||||
K(Var, "var", 0) \
|
||||
K(View, "view", 0) \
|
||||
K(Virtual, "virtual", 0) \
|
||||
K(While, "while", 0) \
|
||||
\
|
||||
/* Ether subdenominations */ \
|
||||
K(SubWei, "wei", 0) \
|
||||
K(SubSzabo, "szabo", 0) \
|
||||
K(SubFinney, "finney", 0) \
|
||||
K(SubGwei, "gwei", 0) \
|
||||
K(SubEther, "ether", 0) \
|
||||
K(SubSecond, "seconds", 0) \
|
||||
K(SubMinute, "minutes", 0) \
|
||||
@ -232,7 +230,6 @@ namespace solidity::langutil
|
||||
\
|
||||
/* Identifiers (not keywords or future reserved words). */ \
|
||||
T(Identifier, nullptr, 0) \
|
||||
T(SubGwei, "gwei", 0) \
|
||||
\
|
||||
/* Keywords reserved for future use. */ \
|
||||
K(After, "after", 0) \
|
||||
@ -267,6 +264,7 @@ namespace solidity::langutil
|
||||
K(Typedef, "typedef", 0) \
|
||||
K(TypeOf, "typeof", 0) \
|
||||
K(Unchecked, "unchecked", 0) \
|
||||
K(Var, "var", 0) \
|
||||
\
|
||||
/* Illegal token - not able to scan. */ \
|
||||
T(Illegal, "ILLEGAL", 0) \
|
||||
@ -307,13 +305,12 @@ namespace TokenTraits
|
||||
constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External; }
|
||||
constexpr bool isLocationSpecifier(Token op) { return op == Token::Memory || op == Token::Storage || op == Token::CallData; }
|
||||
|
||||
constexpr bool isStateMutabilitySpecifier(Token op, bool _allowConstant = true)
|
||||
constexpr bool isStateMutabilitySpecifier(Token op)
|
||||
{
|
||||
return (op == Token::Constant && _allowConstant)
|
||||
|| op == Token::Pure || op == Token::View || op == Token::Payable;
|
||||
return op == Token::Pure || op == Token::View || op == Token::Payable;
|
||||
}
|
||||
|
||||
constexpr bool isEtherSubdenomination(Token op) { return op == Token::SubWei || op == Token::SubSzabo || op == Token::SubFinney || op == Token::SubEther; }
|
||||
constexpr bool isEtherSubdenomination(Token op) { return op >= Token::SubWei && op <= Token::SubEther; }
|
||||
constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; }
|
||||
constexpr bool isReservedKeyword(Token op) { return (Token::After <= op && op <= Token::Unchecked); }
|
||||
|
||||
|
@ -122,8 +122,9 @@ void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contr
|
||||
/// Checks that two events with the same name defined in this contract have different
|
||||
/// argument types
|
||||
map<string, vector<EventDefinition const*>> events;
|
||||
for (EventDefinition const* event: _contract.events())
|
||||
events[event->name()].push_back(event);
|
||||
for (auto const* contract: _contract.annotation().linearizedBaseContracts)
|
||||
for (EventDefinition const* event: contract->events())
|
||||
events[event->name()].push_back(event);
|
||||
|
||||
findDuplicateDefinitions(events);
|
||||
}
|
||||
|
@ -113,18 +113,16 @@ bool DeclarationTypeChecker::visit(StructDefinition const& _struct)
|
||||
for (ASTPointer<VariableDeclaration> const& member: _struct.members())
|
||||
{
|
||||
Type const* memberType = member->annotation().type;
|
||||
while (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||
{
|
||||
if (arrayType->isDynamicallySized())
|
||||
break;
|
||||
memberType = arrayType->baseType();
|
||||
}
|
||||
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||
memberType = arrayType->finalBaseType(true);
|
||||
|
||||
if (auto structType = dynamic_cast<StructType const*>(memberType))
|
||||
if (_cycleDetector.run(structType->structDefinition()))
|
||||
return;
|
||||
}
|
||||
};
|
||||
if (util::CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
|
||||
if (util::CycleDetector<StructDefinition>(visitor).run(_struct))
|
||||
m_errorReporter.fatalTypeError(2046_error, _struct.location(), "Recursive struct definition.");
|
||||
|
||||
return false;
|
||||
@ -296,15 +294,6 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
||||
"The \"immutable\" keyword can only be used for state variables."
|
||||
);
|
||||
|
||||
if (!_variable.typeName())
|
||||
{
|
||||
// This can still happen in very unusual cases where a developer uses constructs, such as
|
||||
// `var a;`, however, such code will have generated errors already.
|
||||
// However, we cannot blindingly solAssert() for that here, as the TypeChecker (which is
|
||||
// invoking ReferencesResolver) is generating it, so the error is most likely(!) generated
|
||||
// after this step.
|
||||
return;
|
||||
}
|
||||
using Location = VariableDeclaration::Location;
|
||||
Location varLoc = _variable.referenceLocation();
|
||||
DataLocation typeLoc = DataLocation::Memory;
|
||||
@ -385,7 +374,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
|
||||
solAssert(!_variable.hasReferenceOrMappingType(), "Data location not properly set.");
|
||||
}
|
||||
|
||||
TypePointer type = _variable.typeName()->annotation().type;
|
||||
TypePointer type = _variable.typeName().annotation().type;
|
||||
if (auto ref = dynamic_cast<ReferenceType const*>(type))
|
||||
{
|
||||
bool isPointer = !_variable.isStateVariable();
|
||||
|
@ -61,25 +61,12 @@ bool DocStringTagParser::visit(VariableDeclaration const& _variable)
|
||||
{
|
||||
if (_variable.isStateVariable())
|
||||
{
|
||||
static set<string> const validPublicTags = set<string>{"dev", "notice", "return", "title", "author", "inheritdoc"};
|
||||
static set<string> const validPublicTags = set<string>{"dev", "notice", "return", "inheritdoc"};
|
||||
static set<string> const validNonPublicTags = set<string>{"dev", "inheritdoc"};
|
||||
if (_variable.isPublic())
|
||||
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "public state variables");
|
||||
else
|
||||
{
|
||||
parseDocStrings(_variable, _variable.annotation(), validPublicTags, "non-public state variables");
|
||||
if (_variable.annotation().docTags.count("notice") > 0)
|
||||
m_errorReporter.warning(
|
||||
7816_error, _variable.documentation()->location(),
|
||||
"Documentation tag on non-public state variables will be disallowed in 0.7.0. "
|
||||
"You will need to use the @dev tag explicitly."
|
||||
);
|
||||
}
|
||||
if (_variable.annotation().docTags.count("title") > 0 || _variable.annotation().docTags.count("author") > 0)
|
||||
m_errorReporter.warning(
|
||||
8532_error, _variable.documentation()->location(),
|
||||
"Documentation tag @title and @author is only allowed on contract definitions. "
|
||||
"It will be disallowed in 0.7.0."
|
||||
);
|
||||
parseDocStrings(_variable, _variable.annotation(), validNonPublicTags, "non-public state variables");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@ -139,8 +126,8 @@ void DocStringTagParser::handleCallable(
|
||||
StructurallyDocumentedAnnotation& _annotation
|
||||
)
|
||||
{
|
||||
static set<string> const validEventTags = set<string>{"author", "dev", "notice", "return", "param"};
|
||||
static set<string> const validTags = set<string>{"author", "dev", "notice", "return", "param", "inheritdoc"};
|
||||
static set<string> const validEventTags = set<string>{"dev", "notice", "return", "param"};
|
||||
static set<string> const validTags = set<string>{"dev", "notice", "return", "param", "inheritdoc"};
|
||||
|
||||
if (dynamic_cast<EventDefinition const*>(&_callable))
|
||||
parseDocStrings(_node, _annotation, validEventTags, "events");
|
||||
@ -148,13 +135,6 @@ void DocStringTagParser::handleCallable(
|
||||
parseDocStrings(_node, _annotation, validTags, "functions");
|
||||
|
||||
checkParameters(_callable, _node, _annotation);
|
||||
|
||||
if (_node.documentation() && _annotation.docTags.count("author") > 0)
|
||||
m_errorReporter.warning(
|
||||
9843_error, _node.documentation()->location(),
|
||||
"Documentation tag @author is only allowed on contract definitions. "
|
||||
"It will be disallowed in 0.7.0."
|
||||
);
|
||||
}
|
||||
|
||||
void DocStringTagParser::parseDocStrings(
|
||||
|
@ -290,7 +290,7 @@ StateMutability OverrideProxy::stateMutability() const
|
||||
return std::visit(GenericVisitor{
|
||||
[&](FunctionDefinition const* _item) { return _item->stateMutability(); },
|
||||
[&](ModifierDefinition const*) { solAssert(false, "Requested state mutability from modifier."); return StateMutability{}; },
|
||||
[&](VariableDeclaration const*) { return StateMutability::View; }
|
||||
[&](VariableDeclaration const* _var) { return _var->isConstant() ? StateMutability::Pure : StateMutability::View; }
|
||||
}, m_item);
|
||||
}
|
||||
|
||||
@ -585,29 +585,35 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
|
||||
"Overridden " + _overriding.astNodeName() + " is here:"
|
||||
);
|
||||
|
||||
// This is only relevant for a function overriding a function.
|
||||
if (_overriding.isFunction())
|
||||
{
|
||||
if (_overriding.stateMutability() != _super.stateMutability())
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
6959_error,
|
||||
"Overriding function changes state mutability from \"" +
|
||||
stateMutabilityToString(_super.stateMutability()) +
|
||||
"\" to \"" +
|
||||
stateMutabilityToString(_overriding.stateMutability()) +
|
||||
"\"."
|
||||
);
|
||||
// Stricter mutability is always okay except when super is Payable
|
||||
if (
|
||||
(_overriding.isFunction() || _overriding.isVariable()) &&
|
||||
(
|
||||
_overriding.stateMutability() > _super.stateMutability() ||
|
||||
_super.stateMutability() == StateMutability::Payable
|
||||
) &&
|
||||
_overriding.stateMutability() != _super.stateMutability()
|
||||
)
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
6959_error,
|
||||
"Overriding " +
|
||||
_overriding.astNodeName() +
|
||||
" changes state mutability from \"" +
|
||||
stateMutabilityToString(_super.stateMutability()) +
|
||||
"\" to \"" +
|
||||
stateMutabilityToString(_overriding.stateMutability()) +
|
||||
"\"."
|
||||
);
|
||||
|
||||
if (_overriding.unimplemented() && !_super.unimplemented())
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
4593_error,
|
||||
"Overriding an implemented function with an unimplemented function is not allowed."
|
||||
);
|
||||
}
|
||||
if (_overriding.unimplemented() && !_super.unimplemented())
|
||||
overrideError(
|
||||
_overriding,
|
||||
_super,
|
||||
4593_error,
|
||||
"Overriding an implemented function with an unimplemented function is not allowed."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,15 +34,16 @@
|
||||
#include <liblangutil/Exceptions.h>
|
||||
|
||||
#include <libsolutil/StringUtils.h>
|
||||
#include <libsolutil/CommonData.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::langutil;
|
||||
using namespace solidity::frontend;
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
bool ReferencesResolver::resolve(ASTNode const& _root)
|
||||
{
|
||||
@ -202,6 +203,10 @@ bool ReferencesResolver::visit(Return const& _return)
|
||||
|
||||
void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
|
||||
{
|
||||
validateYulIdentifierName(_function.name, _function.location);
|
||||
for (yul::TypedName const& varName: _function.parameters + _function.returnVariables)
|
||||
validateYulIdentifierName(varName.name, varName.location);
|
||||
|
||||
bool wasInsideFunction = m_yulInsideFunction;
|
||||
m_yulInsideFunction = true;
|
||||
this->operator()(_function.body);
|
||||
@ -210,9 +215,10 @@ void ReferencesResolver::operator()(yul::FunctionDefinition const& _function)
|
||||
|
||||
void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
{
|
||||
bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot");
|
||||
bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset");
|
||||
bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), ".slot");
|
||||
bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), ".offset");
|
||||
|
||||
// Could also use `pathFromCurrentScope`, split by '.'
|
||||
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
|
||||
if (isSlot || isOffset)
|
||||
{
|
||||
@ -222,19 +228,22 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
return;
|
||||
string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - (
|
||||
isSlot ?
|
||||
string("_slot").size() :
|
||||
string("_offset").size()
|
||||
string(".slot").size() :
|
||||
string(".offset").size()
|
||||
));
|
||||
if (realName.empty())
|
||||
{
|
||||
m_errorReporter.declarationError(
|
||||
4794_error,
|
||||
_identifier.location,
|
||||
"In variable names _slot and _offset can only be used as a suffix."
|
||||
"In variable names .slot and .offset can only be used as a suffix."
|
||||
);
|
||||
return;
|
||||
}
|
||||
declarations = m_resolver.nameFromCurrentScope(realName);
|
||||
if (!declarations.empty())
|
||||
// To support proper path resolution, we have to use pathFromCurrentScope.
|
||||
solAssert(!util::contains(realName, '.'), "");
|
||||
}
|
||||
if (declarations.size() > 1)
|
||||
{
|
||||
@ -246,7 +255,18 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
|
||||
return;
|
||||
}
|
||||
else if (declarations.size() == 0)
|
||||
{
|
||||
if (
|
||||
boost::algorithm::ends_with(_identifier.name.str(), "_slot") ||
|
||||
boost::algorithm::ends_with(_identifier.name.str(), "_offset")
|
||||
)
|
||||
m_errorReporter.declarationError(
|
||||
9467_error,
|
||||
_identifier.location,
|
||||
"Identifier not found. Use ``.slot`` and ``.offset`` to access storage variables."
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (auto var = dynamic_cast<VariableDeclaration const*>(declarations.front()))
|
||||
if (var->isLocalVariable() && m_yulInsideFunction)
|
||||
{
|
||||
@ -267,18 +287,11 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
||||
{
|
||||
for (auto const& identifier: _varDecl.variables)
|
||||
{
|
||||
bool isSlot = boost::algorithm::ends_with(identifier.name.str(), "_slot");
|
||||
bool isOffset = boost::algorithm::ends_with(identifier.name.str(), "_offset");
|
||||
validateYulIdentifierName(identifier.name, identifier.location);
|
||||
|
||||
string namePrefix = identifier.name.str().substr(0, identifier.name.str().find('.'));
|
||||
if (isSlot || isOffset)
|
||||
m_errorReporter.declarationError(
|
||||
9155_error,
|
||||
identifier.location,
|
||||
"In variable declarations _slot and _offset can not be used as a suffix."
|
||||
);
|
||||
else if (
|
||||
auto declarations = m_resolver.nameFromCurrentScope(namePrefix);
|
||||
|
||||
if (
|
||||
auto declarations = m_resolver.nameFromCurrentScope(identifier.name.str());
|
||||
!declarations.empty()
|
||||
)
|
||||
{
|
||||
@ -290,8 +303,6 @@ void ReferencesResolver::operator()(yul::VariableDeclaration const& _varDecl)
|
||||
3859_error,
|
||||
identifier.location,
|
||||
ssl,
|
||||
namePrefix.size() < identifier.name.str().size() ?
|
||||
"The prefix of this declaration conflicts with a declaration outside the inline assembly block." :
|
||||
"This declaration shadows a declaration outside the inline assembly block."
|
||||
);
|
||||
}
|
||||
@ -350,4 +361,12 @@ void ReferencesResolver::resolveInheritDoc(StructuredDocumentation const& _docum
|
||||
}
|
||||
}
|
||||
|
||||
void ReferencesResolver::validateYulIdentifierName(yul::YulString _name, SourceLocation const& _location)
|
||||
{
|
||||
if (util::contains(_name.str(), '.'))
|
||||
m_errorReporter.declarationError(
|
||||
3927_error,
|
||||
_location,
|
||||
"User-defined identifiers in inline assembly cannot contain '.'."
|
||||
);
|
||||
}
|
||||
|
@ -92,6 +92,9 @@ private:
|
||||
|
||||
void resolveInheritDoc(StructuredDocumentation const& _documentation, StructurallyDocumentedAnnotation& _annotation);
|
||||
|
||||
/// Checks if the name contains a '.'.
|
||||
void validateYulIdentifierName(yul::YulString _name, langutil::SourceLocation const& _location);
|
||||
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
NameAndTypeResolver& m_resolver;
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
|
@ -302,7 +302,7 @@ bool SyntaxChecker::visit(ContractDefinition const& _contract)
|
||||
|
||||
bool SyntaxChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
if (_function.noVisibilitySpecified())
|
||||
if (!_function.isConstructor() && _function.noVisibilitySpecified())
|
||||
{
|
||||
string suggestedVisibility = _function.isFallback() || _function.isReceive() || m_isInterface ? "external" : "public";
|
||||
m_errorReporter.syntaxError(
|
||||
|
@ -327,10 +327,14 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
{
|
||||
if (_function.markedVirtual())
|
||||
{
|
||||
if (_function.annotation().contract->isInterface())
|
||||
if (_function.isConstructor())
|
||||
m_errorReporter.typeError(7001_error, _function.location(), "Constructors cannot be virtual.");
|
||||
else if (_function.annotation().contract->isInterface())
|
||||
m_errorReporter.warning(5815_error, _function.location(), "Interface functions are implicitly \"virtual\"");
|
||||
if (_function.visibility() == Visibility::Private)
|
||||
else if (_function.visibility() == Visibility::Private)
|
||||
m_errorReporter.typeError(3942_error, _function.location(), "\"virtual\" and \"private\" cannot be used together.");
|
||||
else if (_function.libraryFunction())
|
||||
m_errorReporter.typeError(7801_error, _function.location(), "Library functions cannot be \"virtual\".");
|
||||
}
|
||||
|
||||
if (_function.isPayable())
|
||||
@ -340,45 +344,62 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
if (_function.isOrdinary() && !_function.isPartOfExternalInterface())
|
||||
m_errorReporter.typeError(5587_error, _function.location(), "\"internal\" and \"private\" functions cannot be payable.");
|
||||
}
|
||||
auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& var) {
|
||||
if (type(var)->category() == Type::Category::Mapping)
|
||||
{
|
||||
if (var.referenceLocation() != VariableDeclaration::Location::Storage)
|
||||
{
|
||||
if (!_function.libraryFunction() && _function.isPublic())
|
||||
m_errorReporter.typeError(3442_error, var.location(), "Mapping types can only have a data location of \"storage\" and thus only be parameters or return variables for internal or library functions.");
|
||||
else
|
||||
m_errorReporter.typeError(5380_error, var.location(), "Mapping types can only have a data location of \"storage\"." );
|
||||
}
|
||||
else
|
||||
solAssert(_function.libraryFunction() || !_function.isPublic(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!type(var)->canLiveOutsideStorage() && _function.isPublic())
|
||||
m_errorReporter.typeError(3312_error, var.location(), "Type is required to live outside storage.");
|
||||
if (_function.isPublic())
|
||||
{
|
||||
auto iType = type(var)->interfaceType(_function.libraryFunction());
|
||||
|
||||
if (!iType)
|
||||
{
|
||||
solAssert(!iType.message().empty(), "Expected detailed error message!");
|
||||
m_errorReporter.fatalTypeError(4103_error, var.location(), iType.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
vector<VariableDeclaration const*> internalParametersInConstructor;
|
||||
|
||||
auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& _var) {
|
||||
if (type(_var)->containsNestedMapping())
|
||||
if (_var.referenceLocation() == VariableDeclaration::Location::Storage)
|
||||
solAssert(
|
||||
_function.libraryFunction() || _function.isConstructor() || !_function.isPublic(),
|
||||
"Mapping types for parameters or return variables "
|
||||
"can only be used in internal or library functions."
|
||||
);
|
||||
bool functionIsExternallyVisible =
|
||||
(!_function.isConstructor() && _function.isPublic()) ||
|
||||
(_function.isConstructor() && !m_currentContract->abstract());
|
||||
if (
|
||||
_function.isPublic() &&
|
||||
!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) &&
|
||||
!typeSupportedByOldABIEncoder(*type(var), _function.libraryFunction())
|
||||
_function.isConstructor() &&
|
||||
_var.referenceLocation() == VariableDeclaration::Location::Storage &&
|
||||
!m_currentContract->abstract()
|
||||
)
|
||||
m_errorReporter.typeError(
|
||||
4957_error,
|
||||
var.location(),
|
||||
"This type is only supported in ABIEncoderV2. "
|
||||
"Use \"pragma experimental ABIEncoderV2;\" to enable the feature."
|
||||
3644_error,
|
||||
_var.location(),
|
||||
"This parameter has a type that can only be used internally. "
|
||||
"You can make the contract abstract to avoid this problem."
|
||||
);
|
||||
else if (functionIsExternallyVisible)
|
||||
{
|
||||
auto iType = type(_var)->interfaceType(_function.libraryFunction());
|
||||
|
||||
if (!iType)
|
||||
{
|
||||
string message = iType.message();
|
||||
solAssert(!message.empty(), "Expected detailed error message!");
|
||||
if (_function.isConstructor())
|
||||
message += " You can make the contract abstract to avoid this problem.";
|
||||
m_errorReporter.typeError(4103_error, _var.location(), message);
|
||||
}
|
||||
else if (
|
||||
!experimentalFeatureActive(ExperimentalFeature::ABIEncoderV2) &&
|
||||
!typeSupportedByOldABIEncoder(*type(_var), _function.libraryFunction())
|
||||
)
|
||||
{
|
||||
string message =
|
||||
"This type is only supported in ABIEncoderV2. "
|
||||
"Use \"pragma experimental ABIEncoderV2;\" to enable the feature.";
|
||||
if (_function.isConstructor())
|
||||
message +=
|
||||
" Alternatively, make the contract abstract and supply the "
|
||||
"constructor arguments from a derived contract.";
|
||||
m_errorReporter.typeError(
|
||||
4957_error,
|
||||
_var.location(),
|
||||
message
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
for (ASTPointer<VariableDeclaration> const& var: _function.parameters())
|
||||
{
|
||||
@ -390,6 +411,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
checkArgumentAndReturnParameter(*var);
|
||||
var->accept(*this);
|
||||
}
|
||||
|
||||
set<Declaration const*> modifiers;
|
||||
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
|
||||
{
|
||||
@ -415,11 +437,10 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
if (_function.isImplemented())
|
||||
m_errorReporter.typeError(4726_error, _function.location(), "Functions in interfaces cannot have an implementation.");
|
||||
|
||||
if (_function.visibility() != Visibility::External)
|
||||
m_errorReporter.typeError(1560_error, _function.location(), "Functions in interfaces must be declared external.");
|
||||
|
||||
if (_function.isConstructor())
|
||||
m_errorReporter.typeError(6482_error, _function.location(), "Constructor cannot be defined in interfaces.");
|
||||
else if (_function.visibility() != Visibility::External)
|
||||
m_errorReporter.typeError(1560_error, _function.location(), "Functions in interfaces must be declared external.");
|
||||
}
|
||||
else if (m_currentContract->contractKind() == ContractKind::Library)
|
||||
if (_function.isConstructor())
|
||||
@ -446,8 +467,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
|
||||
bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
{
|
||||
if (_variable.typeName())
|
||||
_variable.typeName()->accept(*this);
|
||||
_variable.typeName().accept(*this);
|
||||
|
||||
// type is filled either by ReferencesResolver directly from the type name or by
|
||||
// TypeChecker at the VariableDeclarationStatement level.
|
||||
@ -459,9 +479,13 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
m_errorReporter.typeError(1273_error, _variable.location(), "The type of a variable cannot be a library.");
|
||||
if (_variable.value())
|
||||
{
|
||||
if (_variable.isStateVariable() && dynamic_cast<MappingType const*>(varType))
|
||||
if (_variable.isStateVariable() && varType->containsNestedMapping())
|
||||
{
|
||||
m_errorReporter.typeError(6280_error, _variable.location(), "Mappings cannot be assigned to.");
|
||||
m_errorReporter.typeError(
|
||||
6280_error,
|
||||
_variable.location(),
|
||||
"Types in storage containing (nested) mappings cannot be assigned to."
|
||||
);
|
||||
_variable.value()->accept(*this);
|
||||
}
|
||||
else
|
||||
@ -501,9 +525,16 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
|
||||
if (!_variable.isStateVariable())
|
||||
{
|
||||
if (varType->dataStoredIn(DataLocation::Memory) || varType->dataStoredIn(DataLocation::CallData))
|
||||
if (!varType->canLiveOutsideStorage())
|
||||
m_errorReporter.typeError(4061_error, _variable.location(), "Type " + varType->toString() + " is only valid in storage.");
|
||||
if (
|
||||
_variable.referenceLocation() == VariableDeclaration::Location::CallData ||
|
||||
_variable.referenceLocation() == VariableDeclaration::Location::Memory
|
||||
)
|
||||
if (varType->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
4061_error,
|
||||
_variable.location(),
|
||||
"Type " + varType->toString(true) + " is only valid in storage because it contains a (nested) mapping."
|
||||
);
|
||||
}
|
||||
else if (_variable.visibility() >= Visibility::Public)
|
||||
{
|
||||
@ -534,7 +565,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
if (auto referenceType = dynamic_cast<ReferenceType const*>(varType))
|
||||
{
|
||||
auto result = referenceType->validForLocation(referenceType->location());
|
||||
if (result && _variable.isPublicCallableParameter())
|
||||
if (result && (_variable.isConstructorParameter() || _variable.isPublicCallableParameter()))
|
||||
result = referenceType->validForLocation(DataLocation::CallData);
|
||||
if (!result)
|
||||
{
|
||||
@ -560,15 +591,11 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
if (_variable.isStateVariable())
|
||||
m_errorReporter.warning(3408_error, _variable.location(), collisionMessage(_variable.name(), true));
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
2332_error,
|
||||
_variable.typeName() ? _variable.typeName()->location() : _variable.location(),
|
||||
collisionMessage(varType->canonicalName(), false)
|
||||
);
|
||||
m_errorReporter.warning(2332_error, _variable.typeName().location(), collisionMessage(varType->canonicalName(), false));
|
||||
}
|
||||
vector<Type const*> oversizedSubtypes = frontend::oversizedSubtypes(*varType);
|
||||
for (Type const* subtype: oversizedSubtypes)
|
||||
m_errorReporter.warning(7325_error, _variable.typeName()->location(), collisionMessage(subtype->canonicalName(), false));
|
||||
m_errorReporter.warning(7325_error, _variable.typeName().location(), collisionMessage(subtype->canonicalName(), false));
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -646,8 +673,12 @@ bool TypeChecker::visit(EventDefinition const& _eventDef)
|
||||
{
|
||||
if (var->isIndexed())
|
||||
numIndexed++;
|
||||
if (!type(*var)->canLiveOutsideStorage())
|
||||
m_errorReporter.typeError(3448_error, var->location(), "Type is required to live outside storage.");
|
||||
if (type(*var)->containsNestedMapping())
|
||||
m_errorReporter.typeError(
|
||||
3448_error,
|
||||
var->location(),
|
||||
"Type containing a (nested) mapping is not allowed as event parameter type."
|
||||
);
|
||||
if (!type(*var)->interfaceType(false))
|
||||
m_errorReporter.typeError(3417_error, var->location(), "Internal or recursive type is not allowed as event parameter type.");
|
||||
if (
|
||||
@ -724,7 +755,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else if (requiresStorage)
|
||||
{
|
||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes _offset and _slot can only be used on non-constant storage variables.");
|
||||
m_errorReporter.typeError(6617_error, _identifier.location, "The suffixes .offset and .slot can only be used on non-constant storage variables.");
|
||||
return false;
|
||||
}
|
||||
else if (var && var->value() && !var->value()->annotation().type && !dynamic_cast<Literal const*>(var->value().get()))
|
||||
@ -752,7 +783,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
{
|
||||
if (!var->isStateVariable() && !var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
m_errorReporter.typeError(3622_error, _identifier.location, "The suffixes .offset and .slot can only be used on storage variables.");
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
@ -764,7 +795,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else if (identifierInfo.isOffset)
|
||||
{
|
||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only _slot can be assigned to.");
|
||||
m_errorReporter.typeError(9739_error, _identifier.location, "Only .slot can be assigned to.");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
@ -773,12 +804,12 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else if (!var->isConstant() && var->isStateVariable())
|
||||
{
|
||||
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the _slot and _offset suffixes.");
|
||||
m_errorReporter.typeError(1408_error, _identifier.location, "Only local variables are supported. To access storage variables, use the .slot and .offset suffixes.");
|
||||
return false;
|
||||
}
|
||||
else if (var->type()->dataStoredIn(DataLocation::Storage))
|
||||
{
|
||||
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the _slot or _offset suffix to access storage reference variables.");
|
||||
m_errorReporter.typeError(9068_error, _identifier.location, "You have to use the .slot or .offset suffix to access storage reference variables.");
|
||||
return false;
|
||||
}
|
||||
else if (var->type()->sizeOnStack() != 1)
|
||||
@ -792,7 +823,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
else if (requiresStorage)
|
||||
{
|
||||
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes _offset and _slot can only be used on storage variables.");
|
||||
m_errorReporter.typeError(7944_error, _identifier.location, "The suffixes .offset and .slot can only be used on storage variables.");
|
||||
return false;
|
||||
}
|
||||
else if (_context == yul::IdentifierContext::LValue)
|
||||
@ -1071,81 +1102,23 @@ void TypeChecker::endVisit(EmitStatement const& _emit)
|
||||
m_errorReporter.typeError(9292_error, _emit.eventCall().expression().location(), "Expression has to be an event invocation.");
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
/**
|
||||
* @returns a suggested left-hand-side of a multi-variable declaration contairing
|
||||
* the variable declarations given in @a _decls.
|
||||
*/
|
||||
string createTupleDecl(vector<ASTPointer<VariableDeclaration>> const& _decls)
|
||||
{
|
||||
vector<string> components;
|
||||
for (ASTPointer<VariableDeclaration> const& decl: _decls)
|
||||
if (decl)
|
||||
{
|
||||
solAssert(decl->annotation().type, "");
|
||||
components.emplace_back(decl->annotation().type->toString(false) + " " + decl->name());
|
||||
}
|
||||
else
|
||||
components.emplace_back();
|
||||
|
||||
if (_decls.size() == 1)
|
||||
return components.front();
|
||||
else
|
||||
return "(" + boost::algorithm::join(components, ", ") + ")";
|
||||
}
|
||||
|
||||
bool typeCanBeExpressed(vector<ASTPointer<VariableDeclaration>> const& decls)
|
||||
{
|
||||
for (ASTPointer<VariableDeclaration> const& decl: decls)
|
||||
{
|
||||
// skip empty tuples (they can be expressed of course)
|
||||
if (!decl)
|
||||
continue;
|
||||
|
||||
if (!decl->annotation().type)
|
||||
return false;
|
||||
|
||||
if (auto functionType = dynamic_cast<FunctionType const*>(decl->annotation().type))
|
||||
if (
|
||||
functionType->kind() != FunctionType::Kind::Internal &&
|
||||
functionType->kind() != FunctionType::Kind::External
|
||||
)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
{
|
||||
if (!_statement.initialValue())
|
||||
{
|
||||
// No initial value is only permitted for single variables with specified type.
|
||||
// This usually already results in a parser error.
|
||||
if (_statement.declarations().size() != 1 || !_statement.declarations().front())
|
||||
{
|
||||
if (std::all_of(
|
||||
_statement.declarations().begin(),
|
||||
_statement.declarations().end(),
|
||||
[](ASTPointer<VariableDeclaration> const& declaration) { return declaration == nullptr; }
|
||||
))
|
||||
{
|
||||
// The syntax checker has already generated an error for this case (empty LHS tuple).
|
||||
solAssert(m_errorReporter.hasErrors(), "");
|
||||
solAssert(m_errorReporter.hasErrors(), "");
|
||||
|
||||
// It is okay to return here, as there are no named components on the
|
||||
// left-hand-side that could cause any damage later.
|
||||
return false;
|
||||
}
|
||||
else
|
||||
// Bailing out *fatal* here, as those (untyped) vars may be used later, and diagnostics wouldn't be helpful then.
|
||||
m_errorReporter.fatalTypeError(4626_error, _statement.location(), "Use of the \"var\" keyword is disallowed.");
|
||||
// It is okay to return here, as there are no named components on the
|
||||
// left-hand-side that could cause any damage later.
|
||||
return false;
|
||||
}
|
||||
|
||||
VariableDeclaration const& varDecl = *_statement.declarations().front();
|
||||
if (!varDecl.annotation().type)
|
||||
m_errorReporter.fatalTypeError(6983_error, _statement.location(), "Use of the \"var\" keyword is disallowed.");
|
||||
solAssert(varDecl.annotation().type, "");
|
||||
|
||||
if (dynamic_cast<MappingType const*>(type(varDecl)))
|
||||
m_errorReporter.typeError(
|
||||
@ -1182,8 +1155,6 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
")."
|
||||
);
|
||||
|
||||
bool autoTypeDeductionNeeded = false;
|
||||
|
||||
for (size_t i = 0; i < min(variables.size(), valueTypes.size()); ++i)
|
||||
{
|
||||
if (!variables[i])
|
||||
@ -1192,95 +1163,45 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
solAssert(!var.value(), "Value has to be tied to statement.");
|
||||
TypePointer const& valueComponentType = valueTypes[i];
|
||||
solAssert(!!valueComponentType, "");
|
||||
if (!var.annotation().type)
|
||||
{
|
||||
autoTypeDeductionNeeded = true;
|
||||
solAssert(var.annotation().type, "");
|
||||
|
||||
// Infer type from value.
|
||||
solAssert(!var.typeName(), "");
|
||||
var.annotation().type = valueComponentType->mobileType();
|
||||
if (!var.annotation().type)
|
||||
{
|
||||
if (valueComponentType->category() == Type::Category::RationalNumber)
|
||||
m_errorReporter.fatalTypeError(
|
||||
6963_error,
|
||||
_statement.initialValue()->location(),
|
||||
"Invalid rational " +
|
||||
valueComponentType->toString() +
|
||||
" (absolute value too large or division by zero)."
|
||||
);
|
||||
else
|
||||
solAssert(false, "");
|
||||
}
|
||||
else if (*var.annotation().type == *TypeProvider::emptyTuple())
|
||||
solAssert(false, "Cannot declare variable with void (empty tuple) type.");
|
||||
else if (valueComponentType->category() == Type::Category::RationalNumber)
|
||||
{
|
||||
string typeName = var.annotation().type->toString(true);
|
||||
string extension;
|
||||
if (auto type = dynamic_cast<IntegerType const*>(var.annotation().type))
|
||||
{
|
||||
unsigned numBits = type->numBits();
|
||||
bool isSigned = type->isSigned();
|
||||
solAssert(numBits > 0, "");
|
||||
string minValue;
|
||||
string maxValue;
|
||||
if (isSigned)
|
||||
{
|
||||
numBits--;
|
||||
minValue = "-" + bigint(bigint(1) << numBits).str();
|
||||
}
|
||||
else
|
||||
minValue = "0";
|
||||
maxValue = bigint((bigint(1) << numBits) - 1).str();
|
||||
extension = ", which can hold values between " + minValue + " and " + maxValue;
|
||||
}
|
||||
else
|
||||
solAssert(dynamic_cast<FixedPointType const*>(var.annotation().type), "Unknown type.");
|
||||
}
|
||||
|
||||
var.accept(*this);
|
||||
}
|
||||
else
|
||||
var.accept(*this);
|
||||
BoolResult result = valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type);
|
||||
if (!result)
|
||||
{
|
||||
var.accept(*this);
|
||||
BoolResult result = valueComponentType->isImplicitlyConvertibleTo(*var.annotation().type);
|
||||
if (!result)
|
||||
auto errorMsg = "Type " +
|
||||
valueComponentType->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
var.annotation().type->toString();
|
||||
if (
|
||||
valueComponentType->category() == Type::Category::RationalNumber &&
|
||||
dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() &&
|
||||
valueComponentType->mobileType()
|
||||
)
|
||||
{
|
||||
auto errorMsg = "Type " +
|
||||
valueComponentType->toString() +
|
||||
" is not implicitly convertible to expected type " +
|
||||
var.annotation().type->toString();
|
||||
if (
|
||||
valueComponentType->category() == Type::Category::RationalNumber &&
|
||||
dynamic_cast<RationalNumberType const&>(*valueComponentType).isFractional() &&
|
||||
valueComponentType->mobileType()
|
||||
)
|
||||
{
|
||||
if (var.annotation().type->operator==(*valueComponentType->mobileType()))
|
||||
m_errorReporter.typeError(
|
||||
5107_error,
|
||||
_statement.location(),
|
||||
errorMsg + ", but it can be explicitly converted."
|
||||
);
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
4486_error,
|
||||
_statement.location(),
|
||||
errorMsg +
|
||||
". Try converting to type " +
|
||||
valueComponentType->mobileType()->toString() +
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
}
|
||||
else
|
||||
m_errorReporter.typeErrorConcatenateDescriptions(
|
||||
9574_error,
|
||||
if (var.annotation().type->operator==(*valueComponentType->mobileType()))
|
||||
m_errorReporter.typeError(
|
||||
5107_error,
|
||||
_statement.location(),
|
||||
errorMsg + ".",
|
||||
result.message()
|
||||
errorMsg + ", but it can be explicitly converted."
|
||||
);
|
||||
else
|
||||
m_errorReporter.typeError(
|
||||
4486_error,
|
||||
_statement.location(),
|
||||
errorMsg +
|
||||
". Try converting to type " +
|
||||
valueComponentType->mobileType()->toString() +
|
||||
" or use an explicit conversion."
|
||||
);
|
||||
}
|
||||
else
|
||||
m_errorReporter.typeErrorConcatenateDescriptions(
|
||||
9574_error,
|
||||
_statement.location(),
|
||||
errorMsg + ".",
|
||||
result.message()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1292,24 +1213,6 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
|
||||
BOOST_THROW_EXCEPTION(FatalError());
|
||||
}
|
||||
|
||||
if (autoTypeDeductionNeeded)
|
||||
{
|
||||
if (!typeCanBeExpressed(variables))
|
||||
m_errorReporter.syntaxError(
|
||||
3478_error,
|
||||
_statement.location(),
|
||||
"Use of the \"var\" keyword is disallowed. "
|
||||
"Type cannot be expressed in syntax."
|
||||
);
|
||||
else
|
||||
m_errorReporter.syntaxError(
|
||||
1719_error,
|
||||
_statement.location(),
|
||||
"Use of the \"var\" keyword is disallowed. "
|
||||
"Use explicit declaration `" + createTupleDecl(variables) + " = ...` instead."
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1420,7 +1323,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const&
|
||||
checkExpressionAssignment(*types[i], *tupleExpression->components()[i]);
|
||||
}
|
||||
}
|
||||
else if (_type.category() == Type::Category::Mapping)
|
||||
else if (_type.nameable() && _type.containsNestedMapping())
|
||||
{
|
||||
bool isLocalOrReturn = false;
|
||||
if (auto const* identifier = dynamic_cast<Identifier const*>(&_expression))
|
||||
@ -1428,7 +1331,7 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const&
|
||||
if (variableDeclaration->isLocalOrReturn())
|
||||
isLocalOrReturn = true;
|
||||
if (!isLocalOrReturn)
|
||||
m_errorReporter.typeError(9214_error, _expression.location(), "Mappings cannot be assigned to.");
|
||||
m_errorReporter.typeError(9214_error, _expression.location(), "Types in storage containing (nested) mappings cannot be assigned to.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1564,8 +1467,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
|
||||
_tuple.location(),
|
||||
"Unable to deduce nameable type for array elements. Try adding explicit type conversion for the first element."
|
||||
);
|
||||
else if (!inlineArrayType->canLiveOutsideStorage())
|
||||
m_errorReporter.fatalTypeError(1545_error, _tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
|
||||
else if (inlineArrayType->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
1545_error,
|
||||
_tuple.location(),
|
||||
"Type " + inlineArrayType->toString(true) + " is only valid in storage."
|
||||
);
|
||||
|
||||
_tuple.annotation().type = TypeProvider::array(DataLocation::Memory, inlineArrayType, types.size());
|
||||
}
|
||||
@ -1906,8 +1813,6 @@ void TypeChecker::typeCheckReceiveFunction(FunctionDefinition const& _function)
|
||||
void TypeChecker::typeCheckConstructor(FunctionDefinition const& _function)
|
||||
{
|
||||
solAssert(_function.isConstructor(), "");
|
||||
if (_function.markedVirtual())
|
||||
m_errorReporter.typeError(7001_error, _function.location(), "Constructors cannot be virtual.");
|
||||
if (_function.overrides())
|
||||
m_errorReporter.typeError(1209_error, _function.location(), "Constructors cannot override.");
|
||||
if (!_function.returnParameters().empty())
|
||||
@ -1920,8 +1825,30 @@ void TypeChecker::typeCheckConstructor(FunctionDefinition const& _function)
|
||||
stateMutabilityToString(_function.stateMutability()) +
|
||||
"\"."
|
||||
);
|
||||
if (_function.visibility() != Visibility::Public && _function.visibility() != Visibility::Internal)
|
||||
m_errorReporter.typeError(9239_error, _function.location(), "Constructor must be public or internal.");
|
||||
if (!_function.noVisibilitySpecified())
|
||||
{
|
||||
auto const& contract = dynamic_cast<ContractDefinition const&>(*_function.scope());
|
||||
if (_function.visibility() != Visibility::Public && _function.visibility() != Visibility::Internal)
|
||||
m_errorReporter.typeError(9239_error, _function.location(), "Constructor cannot have visibility.");
|
||||
else if (_function.isPublic() && contract.abstract())
|
||||
m_errorReporter.declarationError(
|
||||
8295_error,
|
||||
_function.location(),
|
||||
"Abstract contracts cannot have public constructors. Remove the \"public\" keyword to fix this."
|
||||
);
|
||||
else if (!_function.isPublic() && !contract.abstract())
|
||||
m_errorReporter.declarationError(
|
||||
1845_error,
|
||||
_function.location(),
|
||||
"Non-abstract contracts cannot have internal constructors. Remove the \"internal\" keyword and make the contract abstract to fix this."
|
||||
);
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
2462_error,
|
||||
_function.location(),
|
||||
"Visibility for constructor is ignored. If you want the contract to be non-deployable, making it \"abstract\" is sufficient."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void TypeChecker::typeCheckABIEncodeFunctions(
|
||||
@ -2066,24 +1993,8 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
|
||||
toString(parameterTypes.size()) +
|
||||
".";
|
||||
|
||||
// Extend error message in case we try to construct a struct with mapping member.
|
||||
if (isStructConstructorCall)
|
||||
{
|
||||
/// For error message: Struct members that were removed during conversion to memory.
|
||||
TypePointer const expressionType = type(_functionCall.expression());
|
||||
auto const& t = dynamic_cast<TypeType const&>(*expressionType);
|
||||
auto const& structType = dynamic_cast<StructType const&>(*t.actualType());
|
||||
set<string> membersRemovedForStructConstructor = structType.membersMissingInMemory();
|
||||
|
||||
if (!membersRemovedForStructConstructor.empty())
|
||||
{
|
||||
msg += " Members that have to be skipped in memory:";
|
||||
for (auto const& member: membersRemovedForStructConstructor)
|
||||
msg += " " + member;
|
||||
}
|
||||
|
||||
return { isVariadic ? 1123_error : 9755_error, msg };
|
||||
}
|
||||
else if (
|
||||
_functionType->kind() == FunctionType::Kind::BareCall ||
|
||||
_functionType->kind() == FunctionType::Kind::BareCallCode ||
|
||||
@ -2303,6 +2214,12 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
|
||||
|
||||
if (actualType->category() == Type::Category::Struct)
|
||||
{
|
||||
if (actualType->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
9515_error,
|
||||
_functionCall.location(),
|
||||
"Struct containing a (nested) mapping cannot be constructed."
|
||||
);
|
||||
functionType = dynamic_cast<StructType const&>(*actualType).constructorType();
|
||||
funcCallAnno.kind = FunctionCallKind::StructConstructorCall;
|
||||
funcCallAnno.isPure = argumentsArePure;
|
||||
@ -2532,8 +2449,6 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
m_errorReporter.fatalTypeError(5540_error, _newExpression.location(), "Identifier is not a contract.");
|
||||
if (contract->isInterface())
|
||||
m_errorReporter.fatalTypeError(2971_error, _newExpression.location(), "Cannot instantiate an interface.");
|
||||
if (!contract->constructorIsPublic())
|
||||
m_errorReporter.typeError(9054_error, _newExpression.location(), "Contract with internal constructor cannot be created directly.");
|
||||
if (contract->abstract())
|
||||
m_errorReporter.typeError(4614_error, _newExpression.location(), "Cannot instantiate an abstract contract.");
|
||||
|
||||
@ -2554,11 +2469,11 @@ void TypeChecker::endVisit(NewExpression const& _newExpression)
|
||||
}
|
||||
else if (type->category() == Type::Category::Array)
|
||||
{
|
||||
if (!type->canLiveOutsideStorage())
|
||||
if (type->containsNestedMapping())
|
||||
m_errorReporter.fatalTypeError(
|
||||
1164_error,
|
||||
_newExpression.typeName().location(),
|
||||
"Type cannot live outside storage."
|
||||
"Array containing a (nested) mapping cannot be constructed in memory."
|
||||
);
|
||||
if (!type->isDynamicallySized())
|
||||
m_errorReporter.typeError(
|
||||
@ -2716,7 +2631,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
|
||||
!annotation.referencedDeclaration &&
|
||||
(memberName == "value" || memberName == "gas")
|
||||
)
|
||||
m_errorReporter.warning(
|
||||
m_errorReporter.typeError(
|
||||
1621_error,
|
||||
_memberAccess.location(),
|
||||
"Using \"." + memberName + "(...)\" is deprecated. Use \"{" + memberName + ": ...}\" instead."
|
||||
@ -3114,6 +3029,20 @@ bool TypeChecker::visit(Identifier const& _identifier)
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
MagicVariableDeclaration const* magicVar =
|
||||
dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration)
|
||||
)
|
||||
if (magicVar->type()->category() == Type::Category::Integer)
|
||||
{
|
||||
solAssert(_identifier.name() == "now", "");
|
||||
m_errorReporter.typeError(
|
||||
7359_error,
|
||||
_identifier.location(),
|
||||
"\"now\" has been deprecated. Use \"block.timestamp\" instead."
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ void ViewPureChecker::endVisit(FunctionDefinition const& _funDef)
|
||||
!_funDef.isConstructor() &&
|
||||
!_funDef.isFallback() &&
|
||||
!_funDef.isReceive() &&
|
||||
!_funDef.overrides()
|
||||
!_funDef.virtualSemantics()
|
||||
)
|
||||
m_errorReporter.warning(
|
||||
2018_error,
|
||||
|
@ -123,15 +123,9 @@ FunctionDefinition const* ContractDefinition::constructor() const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool ContractDefinition::constructorIsPublic() const
|
||||
{
|
||||
FunctionDefinition const* f = constructor();
|
||||
return !f || f->isPublic();
|
||||
}
|
||||
|
||||
bool ContractDefinition::canBeDeployed() const
|
||||
{
|
||||
return constructorIsPublic() && !abstract() && !isInterface();
|
||||
return !abstract() && !isInterface();
|
||||
}
|
||||
|
||||
FunctionDefinition const* ContractDefinition::fallbackFunction() const
|
||||
@ -295,6 +289,12 @@ bool FunctionDefinition::libraryFunction() const
|
||||
return false;
|
||||
}
|
||||
|
||||
Visibility FunctionDefinition::defaultVisibility() const
|
||||
{
|
||||
solAssert(!isConstructor(), "");
|
||||
return Declaration::defaultVisibility();
|
||||
}
|
||||
|
||||
FunctionTypePointer FunctionDefinition::functionType(bool _internal) const
|
||||
{
|
||||
if (_internal)
|
||||
@ -615,9 +615,8 @@ bool VariableDeclaration::isEventParameter() const
|
||||
|
||||
bool VariableDeclaration::hasReferenceOrMappingType() const
|
||||
{
|
||||
solAssert(typeName(), "");
|
||||
solAssert(typeName()->annotation().type, "Can only be called after reference resolution");
|
||||
Type const* type = typeName()->annotation().type;
|
||||
solAssert(typeName().annotation().type, "Can only be called after reference resolution");
|
||||
Type const* type = typeName().annotation().type;
|
||||
return type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type);
|
||||
}
|
||||
|
||||
@ -630,7 +629,12 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
|
||||
else if (isCallableOrCatchParameter())
|
||||
{
|
||||
set<Location> locations{ Location::Memory };
|
||||
if (isInternalCallableParameter() || isLibraryFunctionParameter() || isTryCatchParameter())
|
||||
if (
|
||||
isConstructorParameter() ||
|
||||
isInternalCallableParameter() ||
|
||||
isLibraryFunctionParameter() ||
|
||||
isTryCatchParameter()
|
||||
)
|
||||
locations.insert(Location::Storage);
|
||||
if (!isTryCatchParameter() && !isConstructorParameter())
|
||||
locations.insert(Location::CallData);
|
||||
@ -638,22 +642,8 @@ set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() c
|
||||
return locations;
|
||||
}
|
||||
else if (isLocalVariable())
|
||||
{
|
||||
solAssert(typeName(), "");
|
||||
auto dataLocations = [](TypePointer _type, auto&& _recursion) -> set<Location> {
|
||||
solAssert(_type, "Can only be called after reference resolution");
|
||||
switch (_type->category())
|
||||
{
|
||||
case Type::Category::Array:
|
||||
return _recursion(dynamic_cast<ArrayType const*>(_type)->baseType(), _recursion);
|
||||
case Type::Category::Mapping:
|
||||
return set<Location>{ Location::Storage };
|
||||
default:
|
||||
return set<Location>{ Location::Memory, Location::Storage, Location::CallData };
|
||||
}
|
||||
};
|
||||
return dataLocations(typeName()->annotation().type, dataLocations);
|
||||
}
|
||||
// Further restrictions will be imposed later on.
|
||||
return set<Location>{ Location::Memory, Location::Storage, Location::CallData };
|
||||
else
|
||||
// Struct members etc.
|
||||
return set<Location>{ Location::Unspecified };
|
||||
|
@ -506,8 +506,6 @@ public:
|
||||
|
||||
/// Returns the constructor or nullptr if no constructor was specified.
|
||||
FunctionDefinition const* constructor() const;
|
||||
/// @returns true iff the constructor of this contract is public (or non-existing).
|
||||
bool constructorIsPublic() const;
|
||||
/// @returns true iff the contract can be deployed, i.e. is not abstract and has a
|
||||
/// public constructor.
|
||||
/// Should only be called after the type checker has run.
|
||||
@ -809,15 +807,16 @@ public:
|
||||
bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
|
||||
std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
|
||||
Block const& body() const { solAssert(m_body, ""); return *m_body; }
|
||||
Visibility defaultVisibility() const override;
|
||||
bool isVisibleInContract() const override
|
||||
{
|
||||
return Declaration::isVisibleInContract() && isOrdinary();
|
||||
return isOrdinary() && Declaration::isVisibleInContract();
|
||||
}
|
||||
bool isVisibleViaContractTypeAccess() const override
|
||||
{
|
||||
return visibility() >= Visibility::Public;
|
||||
return isOrdinary() && visibility() >= Visibility::Public;
|
||||
}
|
||||
bool isPartOfExternalInterface() const override { return isPublic() && isOrdinary(); }
|
||||
bool isPartOfExternalInterface() const override { return isOrdinary() && isPublic(); }
|
||||
|
||||
/// @returns the external signature of the function
|
||||
/// That consists of the name of the function followed by the types of the
|
||||
@ -897,13 +896,16 @@ public:
|
||||
m_isIndexed(_isIndexed),
|
||||
m_mutability(_mutability),
|
||||
m_overrides(std::move(_overrides)),
|
||||
m_location(_referenceLocation) {}
|
||||
m_location(_referenceLocation)
|
||||
{
|
||||
solAssert(m_typeName, "");
|
||||
}
|
||||
|
||||
|
||||
void accept(ASTVisitor& _visitor) override;
|
||||
void accept(ASTConstVisitor& _visitor) const override;
|
||||
|
||||
TypeName* typeName() const { return m_typeName.get(); }
|
||||
TypeName const& typeName() const { return *m_typeName; }
|
||||
ASTPointer<Expression> const& value() const { return m_value; }
|
||||
|
||||
bool isLValue() const override;
|
||||
@ -929,6 +931,7 @@ public:
|
||||
/// @returns true if this variable is a parameter or return parameter of an internal function
|
||||
/// or a function type of internal visibility.
|
||||
bool isInternalCallableParameter() const;
|
||||
/// @returns true if this variable is the parameter of a constructor.
|
||||
bool isConstructorParameter() const;
|
||||
/// @returns true iff this variable is a parameter(or return parameter of a library function
|
||||
bool isLibraryFunctionParameter() const;
|
||||
@ -965,7 +968,7 @@ protected:
|
||||
Visibility defaultVisibility() const override { return Visibility::Internal; }
|
||||
|
||||
private:
|
||||
ASTPointer<TypeName> m_typeName; ///< can be empty ("var")
|
||||
ASTPointer<TypeName> m_typeName;
|
||||
/// Initially assigned value, can be missing. For local variables, this is stored inside
|
||||
/// VariableDeclarationStatement and not here.
|
||||
ASTPointer<Expression> m_value;
|
||||
@ -2087,8 +2090,6 @@ public:
|
||||
None = static_cast<int>(Token::Illegal),
|
||||
Wei = static_cast<int>(Token::SubWei),
|
||||
Gwei = static_cast<int>(Token::SubGwei),
|
||||
Szabo = static_cast<int>(Token::SubSzabo),
|
||||
Finney = static_cast<int>(Token::SubFinney),
|
||||
Ether = static_cast<int>(Token::SubEther),
|
||||
Second = static_cast<int>(Token::SubSecond),
|
||||
Minute = static_cast<int>(Token::SubMinute),
|
||||
|
@ -139,6 +139,9 @@ struct StructDeclarationAnnotation: TypeDeclarationAnnotation
|
||||
/// recursion immediately raises an error.
|
||||
/// Will be filled in by the DeclarationTypeChecker.
|
||||
std::optional<bool> recursive;
|
||||
/// Whether the struct contains a mapping type, either directly or, indirectly inside another
|
||||
/// struct or an array.
|
||||
std::optional<bool> containsNestedMapping;
|
||||
};
|
||||
|
||||
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, StructurallyDocumentedAnnotation
|
||||
|
@ -203,7 +203,7 @@ Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<yul::Identifie
|
||||
|
||||
void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node)
|
||||
{
|
||||
_stream << util::jsonPrettyPrint(toJson(_node));
|
||||
_stream << util::jsonPrettyPrint(util::removeNullMembers(toJson(_node)));
|
||||
}
|
||||
|
||||
Json::Value&& ASTJsonConverter::toJson(ASTNode const& _node)
|
||||
@ -351,12 +351,18 @@ bool ASTJsonConverter::visit(OverrideSpecifier const& _node)
|
||||
|
||||
bool ASTJsonConverter::visit(FunctionDefinition const& _node)
|
||||
{
|
||||
Visibility visibility;
|
||||
if (_node.isConstructor())
|
||||
visibility = _node.annotation().contract->abstract() ? Visibility::Internal : Visibility::Public;
|
||||
else
|
||||
visibility = _node.visibility();
|
||||
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
|
||||
make_pair("kind", TokenTraits::toString(_node.kind())),
|
||||
make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
|
||||
make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
|
||||
make_pair("visibility", Declaration::visibilityToString(visibility)),
|
||||
make_pair("virtual", _node.markedVirtual()),
|
||||
make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
|
||||
make_pair("parameters", toJson(_node.parameterList())),
|
||||
@ -366,6 +372,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
|
||||
make_pair("implemented", _node.isImplemented()),
|
||||
make_pair("scope", idOrNull(_node.scope()))
|
||||
};
|
||||
|
||||
if (_node.isPartOfExternalInterface())
|
||||
attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
|
||||
if (!_node.annotation().baseFunctions.empty())
|
||||
@ -380,7 +387,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node)
|
||||
{
|
||||
std::vector<pair<string, Json::Value>> attributes = {
|
||||
make_pair("name", _node.name()),
|
||||
make_pair("typeName", toJsonOrNull(_node.typeName())),
|
||||
make_pair("typeName", toJson(_node.typeName())),
|
||||
make_pair("constant", _node.isConstant()),
|
||||
make_pair("mutability", VariableDeclaration::mutabilityToString(_node.mutability())),
|
||||
make_pair("stateVariable", _node.isStateVariable()),
|
||||
|
@ -400,7 +400,7 @@ ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(Json::V
|
||||
return createASTNode<FunctionDefinition>(
|
||||
_node,
|
||||
memberAsASTString(_node, "name"),
|
||||
visibility(_node),
|
||||
kind == Token::Constructor ? Visibility::Default : visibility(_node),
|
||||
stateMutability(_node),
|
||||
kind,
|
||||
memberAsBool(_node, "virtual"),
|
||||
@ -886,7 +886,8 @@ ASTPointer<StructuredDocumentation> ASTJsonImporter::createDocumentation(Json::V
|
||||
|
||||
Json::Value ASTJsonImporter::member(Json::Value const& _node, string const& _name)
|
||||
{
|
||||
astAssert(_node.isMember(_name), "Node '" + _node["nodeType"].asString() + "' (id " + _node["id"].asString() + ") is missing field '" + _name + "'.");
|
||||
if (!_node.isMember(_name))
|
||||
return Json::nullValue;
|
||||
return _node[_name];
|
||||
}
|
||||
|
||||
@ -1004,10 +1005,6 @@ Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _no
|
||||
return Literal::SubDenomination::Wei;
|
||||
else if (subDenStr == "gwei")
|
||||
return Literal::SubDenomination::Gwei;
|
||||
else if (subDenStr == "szabo")
|
||||
return Literal::SubDenomination::Szabo;
|
||||
else if (subDenStr == "finney")
|
||||
return Literal::SubDenomination::Finney;
|
||||
else if (subDenStr == "ether")
|
||||
return Literal::SubDenomination::Ether;
|
||||
else if (subDenStr == "seconds")
|
||||
|
@ -64,7 +64,8 @@ T AsmJsonImporter::createAsmNode(Json::Value const& _node)
|
||||
|
||||
Json::Value AsmJsonImporter::member(Json::Value const& _node, string const& _name)
|
||||
{
|
||||
astAssert(_node.isMember(_name), "Node is missing field '" + _name + "'.");
|
||||
if (!_node.isMember(_name))
|
||||
return Json::nullValue;
|
||||
return _node[_name];
|
||||
}
|
||||
|
||||
|
@ -97,6 +97,7 @@ public:
|
||||
static IntegerType const* uint(unsigned _bits) { return integer(_bits, IntegerType::Modifier::Unsigned); }
|
||||
|
||||
static IntegerType const* uint256() { return uint(256); }
|
||||
static IntegerType const* int256() { return integer(256, IntegerType::Modifier::Signed); }
|
||||
|
||||
static FixedPointType const* fixedPoint(unsigned m, unsigned n, FixedPointType::Modifier _modifier);
|
||||
|
||||
|
@ -417,11 +417,9 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ASTNode const& _sc
|
||||
if (auto const* sourceUnit = dynamic_cast<SourceUnit const*>(&_scope))
|
||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(sourceUnit->nodes());
|
||||
else if (auto const* contract = dynamic_cast<ContractDefinition const*>(&_scope))
|
||||
{
|
||||
for (ContractDefinition const* contract: contract->annotation().linearizedBaseContracts)
|
||||
usingForDirectives += contract->usingForDirectives();
|
||||
usingForDirectives += ASTNode::filteredNodes<UsingForDirective>(contract->sourceUnit().nodes());
|
||||
}
|
||||
usingForDirectives +=
|
||||
contract->usingForDirectives() +
|
||||
ASTNode::filteredNodes<UsingForDirective>(contract->sourceUnit().nodes());
|
||||
else
|
||||
solAssert(false, "");
|
||||
|
||||
@ -570,7 +568,7 @@ bool isValidShiftAndAmountType(Token _operator, Type const& _shiftAmountType)
|
||||
if (_operator == Token::SHR)
|
||||
return false;
|
||||
else if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(&_shiftAmountType))
|
||||
return true;
|
||||
return !otherInt->isSigned();
|
||||
else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(&_shiftAmountType))
|
||||
return !otherRat->isFractional() && otherRat->integerType() && !otherRat->integerType()->isSigned();
|
||||
else
|
||||
@ -954,12 +952,6 @@ tuple<bool, rational> RationalNumberType::isValidLiteral(Literal const& _literal
|
||||
case Literal::SubDenomination::Gwei:
|
||||
value *= bigint("1000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Szabo:
|
||||
value *= bigint("1000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Finney:
|
||||
value *= bigint("1000000000000000");
|
||||
break;
|
||||
case Literal::SubDenomination::Ether:
|
||||
value *= bigint("1000000000000000000");
|
||||
break;
|
||||
@ -1057,10 +1049,38 @@ TypeResult RationalNumberType::binaryOperatorResult(Token _operator, Type const*
|
||||
{
|
||||
if (_other->category() == Category::Integer || _other->category() == Category::FixedPoint)
|
||||
{
|
||||
auto commonType = Type::commonType(this, _other);
|
||||
if (!commonType)
|
||||
return nullptr;
|
||||
return commonType->binaryOperatorResult(_operator, _other);
|
||||
if (isFractional())
|
||||
return TypeResult::err("Fractional literals not supported.");
|
||||
else if (!integerType())
|
||||
return TypeResult::err("Literal too large.");
|
||||
|
||||
// Shift and exp are not symmetric, so it does not make sense to swap
|
||||
// the types as below. As an exception, we always use uint here.
|
||||
if (TokenTraits::isShiftOp(_operator))
|
||||
{
|
||||
if (!isValidShiftAndAmountType(_operator, *_other))
|
||||
return nullptr;
|
||||
return isNegative() ? TypeProvider::int256() : TypeProvider::uint256();
|
||||
}
|
||||
else if (Token::Exp == _operator)
|
||||
{
|
||||
if (auto const* otherIntType = dynamic_cast<IntegerType const*>(_other))
|
||||
{
|
||||
if (otherIntType->isSigned())
|
||||
return TypeResult::err("Exponentiation power is not allowed to be a signed integer type.");
|
||||
}
|
||||
else if (dynamic_cast<FixedPointType const*>(_other))
|
||||
return TypeResult::err("Exponent is fractional.");
|
||||
|
||||
return isNegative() ? TypeProvider::int256() : TypeProvider::uint256();
|
||||
}
|
||||
else
|
||||
{
|
||||
auto commonType = Type::commonType(this, _other);
|
||||
if (!commonType)
|
||||
return nullptr;
|
||||
return commonType->binaryOperatorResult(_operator, _other);
|
||||
}
|
||||
}
|
||||
else if (_other->category() != category())
|
||||
return nullptr;
|
||||
@ -2032,6 +2052,20 @@ TypeResult ArrayType::interfaceType(bool _inLibrary) const
|
||||
return result;
|
||||
}
|
||||
|
||||
Type const* ArrayType::finalBaseType(bool _breakIfDynamicArrayType) const
|
||||
{
|
||||
Type const* finalBaseType = this;
|
||||
|
||||
while (auto arrayType = dynamic_cast<ArrayType const*>(finalBaseType))
|
||||
{
|
||||
if (_breakIfDynamicArrayType && arrayType->isDynamicallySized())
|
||||
break;
|
||||
finalBaseType = arrayType->baseType();
|
||||
}
|
||||
|
||||
return finalBaseType;
|
||||
}
|
||||
|
||||
u256 ArrayType::memoryDataSize() const
|
||||
{
|
||||
solAssert(!isDynamicallySized(), "");
|
||||
@ -2260,7 +2294,7 @@ unsigned StructType::calldataEncodedSize(bool) const
|
||||
unsigned size = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
// Struct members are always padded.
|
||||
size += member.type->calldataEncodedSize();
|
||||
}
|
||||
@ -2275,7 +2309,7 @@ unsigned StructType::calldataEncodedTailSize() const
|
||||
unsigned size = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
// Struct members are always padded.
|
||||
size += member.type->calldataHeadSize();
|
||||
}
|
||||
@ -2287,7 +2321,7 @@ unsigned StructType::calldataOffsetOfMember(std::string const& _member) const
|
||||
unsigned offset = 0;
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
if (member.name == _member)
|
||||
return offset;
|
||||
// Struct members are always padded.
|
||||
@ -2332,6 +2366,42 @@ u256 StructType::storageSize() const
|
||||
return max<u256>(1, members(nullptr).storageSize());
|
||||
}
|
||||
|
||||
bool StructType::containsNestedMapping() const
|
||||
{
|
||||
if (!m_struct.annotation().containsNestedMapping.has_value())
|
||||
{
|
||||
bool hasNestedMapping = false;
|
||||
|
||||
util::BreadthFirstSearch<StructDefinition const*> breadthFirstSearch{{&m_struct}};
|
||||
|
||||
breadthFirstSearch.run(
|
||||
[&](StructDefinition const* _struct, auto&& _addChild)
|
||||
{
|
||||
for (auto const& member: _struct->members())
|
||||
{
|
||||
TypePointer memberType = member->annotation().type;
|
||||
solAssert(memberType, "");
|
||||
|
||||
if (auto arrayType = dynamic_cast<ArrayType const*>(memberType))
|
||||
memberType = arrayType->finalBaseType(false);
|
||||
|
||||
if (dynamic_cast<MappingType const*>(memberType))
|
||||
{
|
||||
hasNestedMapping = true;
|
||||
breadthFirstSearch.abort();
|
||||
}
|
||||
else if (auto structType = dynamic_cast<StructType const*>(memberType))
|
||||
_addChild(&structType->structDefinition());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
m_struct.annotation().containsNestedMapping = hasNestedMapping;
|
||||
}
|
||||
|
||||
return m_struct.annotation().containsNestedMapping.value();
|
||||
}
|
||||
|
||||
string StructType::toString(bool _short) const
|
||||
{
|
||||
string ret = "struct " + m_struct.annotation().canonicalName;
|
||||
@ -2347,10 +2417,7 @@ MemberList::MemberMap StructType::nativeMembers(ASTNode const*) const
|
||||
{
|
||||
TypePointer type = variable->annotation().type;
|
||||
solAssert(type, "");
|
||||
// If we are not in storage, skip all members that cannot live outside of storage,
|
||||
// ex. mappings and array of mappings
|
||||
if (location() != DataLocation::Storage && !type->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(!(location() != DataLocation::Storage && type->containsNestedMapping()), "");
|
||||
members.emplace_back(
|
||||
variable->name(),
|
||||
copyForLocationIfReference(type),
|
||||
@ -2519,10 +2586,9 @@ FunctionTypePointer StructType::constructorType() const
|
||||
{
|
||||
TypePointers paramTypes;
|
||||
strings paramNames;
|
||||
solAssert(!containsNestedMapping(), "");
|
||||
for (auto const& member: members(nullptr))
|
||||
{
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
continue;
|
||||
paramNames.push_back(member.name);
|
||||
paramTypes.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, member.type));
|
||||
}
|
||||
@ -2556,20 +2622,12 @@ u256 StructType::memoryOffsetOfMember(string const& _name) const
|
||||
|
||||
TypePointers StructType::memoryMemberTypes() const
|
||||
{
|
||||
solAssert(!containsNestedMapping(), "");
|
||||
TypePointers types;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
if (variable->annotation().type->canLiveOutsideStorage())
|
||||
types.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, variable->annotation().type));
|
||||
return types;
|
||||
}
|
||||
types.push_back(TypeProvider::withLocationIfReference(DataLocation::Memory, variable->annotation().type));
|
||||
|
||||
set<string> StructType::membersMissingInMemory() const
|
||||
{
|
||||
set<string> missing;
|
||||
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||
if (!variable->annotation().type->canLiveOutsideStorage())
|
||||
missing.insert(variable->name());
|
||||
return missing;
|
||||
return types;
|
||||
}
|
||||
|
||||
vector<tuple<string, TypePointer>> StructType::makeStackItems() const
|
||||
@ -3716,7 +3774,10 @@ TypeResult MappingType::interfaceType(bool _inLibrary) const
|
||||
}
|
||||
}
|
||||
else
|
||||
return TypeResult::err("Only libraries are allowed to use the mapping type in public or external functions.");
|
||||
return TypeResult::err(
|
||||
"Types containing (nested) mappings can only be parameters or "
|
||||
"return variables of internal or library functions."
|
||||
);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -271,7 +271,11 @@ public:
|
||||
/// Returns true if the type can be stored in storage.
|
||||
virtual bool canBeStored() const { return true; }
|
||||
/// Returns false if the type cannot live outside the storage, i.e. if it includes some mapping.
|
||||
virtual bool canLiveOutsideStorage() const { return true; }
|
||||
virtual bool containsNestedMapping() const
|
||||
{
|
||||
solAssert(nameable(), "Called for a non nameable type.");
|
||||
return false;
|
||||
}
|
||||
/// Returns true if the type can be stored as a value (as opposed to a reference) on the stack,
|
||||
/// i.e. it behaves differently in lvalue context and in value context.
|
||||
virtual bool isValueType() const { return false; }
|
||||
@ -561,7 +565,6 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
u256 literalValue(Literal const* _literal) const override;
|
||||
@ -622,7 +625,6 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
|
||||
std::string toString(bool) const override;
|
||||
TypePointer mobileType() const override;
|
||||
@ -794,8 +796,9 @@ public:
|
||||
bool isDynamicallyEncoded() const override;
|
||||
bigint storageSizeUpperBound() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
|
||||
bool containsNestedMapping() const override { return m_baseType->containsNestedMapping(); }
|
||||
bool nameable() const override { return true; }
|
||||
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||
@ -811,6 +814,7 @@ public:
|
||||
/// @returns true if this is a string
|
||||
bool isString() const { return m_arrayKind == ArrayKind::String; }
|
||||
Type const* baseType() const { solAssert(!!m_baseType, ""); return m_baseType; }
|
||||
Type const* finalBaseType(bool breakIfDynamicArrayType) const;
|
||||
u256 const& length() const { return m_length; }
|
||||
u256 memoryDataSize() const override;
|
||||
|
||||
@ -855,7 +859,6 @@ public:
|
||||
unsigned calldataEncodedTailSize() const override { return 32; }
|
||||
bool isDynamicallySized() const override { return true; }
|
||||
bool isDynamicallyEncoded() const override { return true; }
|
||||
bool canLiveOutsideStorage() const override { return m_arrayType.canLiveOutsideStorage(); }
|
||||
std::string toString(bool _short) const override;
|
||||
TypePointer mobileType() const override;
|
||||
|
||||
@ -896,7 +899,6 @@ public:
|
||||
}
|
||||
unsigned storageBytes() const override { solAssert(!isSuper(), ""); return 20; }
|
||||
bool leftAligned() const override { solAssert(!isSuper(), ""); return false; }
|
||||
bool canLiveOutsideStorage() const override { return !isSuper(); }
|
||||
bool isValueType() const override { return !isSuper(); }
|
||||
bool nameable() const override { return !isSuper(); }
|
||||
std::string toString(bool _short) const override;
|
||||
@ -959,7 +961,7 @@ public:
|
||||
u256 memoryDataSize() const override;
|
||||
bigint storageSizeUpperBound() const override;
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool containsNestedMapping() const override;
|
||||
bool nameable() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
|
||||
@ -989,8 +991,6 @@ public:
|
||||
|
||||
/// @returns the vector of types of members available in memory.
|
||||
TypePointers memoryMemberTypes() const;
|
||||
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
||||
std::set<std::string> membersMissingInMemory() const;
|
||||
|
||||
void clearCache() const override;
|
||||
|
||||
@ -1021,7 +1021,6 @@ public:
|
||||
}
|
||||
unsigned storageBytes() const override;
|
||||
bool leftAligned() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
bool isValueType() const override { return true; }
|
||||
@ -1061,7 +1060,6 @@ public:
|
||||
std::string toString(bool) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
TypePointer mobileType() const override;
|
||||
/// Converts components to their temporary types and performs some wildcard matching.
|
||||
@ -1232,7 +1230,6 @@ public:
|
||||
unsigned storageBytes() const override;
|
||||
bool isValueType() const override { return true; }
|
||||
bool nameable() const override;
|
||||
bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||
bool hasSimpleZeroValueInMemory() const override { return false; }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
TypePointer encodingType() const override;
|
||||
@ -1365,7 +1362,7 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
std::string toString(bool _short) const override;
|
||||
std::string canonicalName() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool containsNestedMapping() const override { return true; }
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
Type const* encodingType() const override;
|
||||
TypeResult interfaceType(bool _inLibrary) const override;
|
||||
@ -1400,7 +1397,6 @@ public:
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const* _currentScope) const override;
|
||||
@ -1426,7 +1422,6 @@ public:
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
bool canBeStored() const override { return false; }
|
||||
u256 storageSize() const override;
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
@ -1453,7 +1448,6 @@ public:
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
|
||||
@ -1493,7 +1487,6 @@ public:
|
||||
std::string richIdentifier() const override;
|
||||
bool operator==(Type const& _other) const override;
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
MemberList::MemberMap nativeMembers(ASTNode const*) const override;
|
||||
|
||||
@ -1526,7 +1519,6 @@ public:
|
||||
TypeResult binaryOperatorResult(Token, Type const*) const override { return nullptr; }
|
||||
unsigned calldataEncodedSize(bool) const override { return 32; }
|
||||
bool canBeStored() const override { return false; }
|
||||
bool canLiveOutsideStorage() const override { return false; }
|
||||
bool isValueType() const override { return true; }
|
||||
bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
|
||||
std::string toString(bool) const override { return "inaccessible dynamic type"; }
|
||||
|
@ -861,8 +861,7 @@ string ABIFunctions::abiEncodingFunctionStruct(
|
||||
for (auto const& member: _to.members(nullptr))
|
||||
{
|
||||
solAssert(member.type, "");
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
TypePointer memberTypeTo = member.type->fullEncodingType(_options.encodeAsLibraryTypes, true, false);
|
||||
solUnimplementedAssert(memberTypeTo, "Encoding type \"" + member.type->toString() + "\" not yet implemented.");
|
||||
auto memberTypeFrom = _from.memberType(member.name);
|
||||
@ -1341,7 +1340,7 @@ string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, bool _fr
|
||||
for (auto const& member: _type.members(nullptr))
|
||||
{
|
||||
solAssert(member.type, "");
|
||||
solAssert(member.type->canLiveOutsideStorage(), "");
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
auto decodingType = member.type->decodingType();
|
||||
solAssert(decodingType, "");
|
||||
bool dynamic = decodingType->isDynamicallyEncoded();
|
||||
|
@ -1080,8 +1080,7 @@ void CompilerUtils::convertType(
|
||||
// stack: <memory ptr> <source ref> <memory ptr>
|
||||
for (auto const& member: typeOnStack->members(nullptr))
|
||||
{
|
||||
if (!member.type->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(!member.type->containsNestedMapping(), "");
|
||||
pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name);
|
||||
_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
|
||||
_context << u256(offsets.second);
|
||||
|
@ -1915,10 +1915,6 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
|
||||
if (!dynamic_cast<ContractType const&>(*magicVar->type()).isSuper())
|
||||
m_context << Instruction::ADDRESS;
|
||||
break;
|
||||
case Type::Category::Integer:
|
||||
// "now"
|
||||
m_context << Instruction::TIMESTAMP;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -356,13 +356,13 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
||||
structType.structDefinition() == sourceType.structDefinition(),
|
||||
"Struct assignment with conversion."
|
||||
);
|
||||
solAssert(!structType.containsNestedMapping(), "");
|
||||
solAssert(sourceType.location() != DataLocation::CallData, "Structs in calldata not supported.");
|
||||
for (auto const& member: structType.members(nullptr))
|
||||
{
|
||||
// assign each member that can live outside of storage
|
||||
TypePointer const& memberType = member.type;
|
||||
if (!memberType->canLiveOutsideStorage())
|
||||
continue;
|
||||
solAssert(memberType->nameable(), "");
|
||||
TypePointer sourceMemberType = sourceType.memberType(member.name);
|
||||
if (sourceType.location() == DataLocation::Storage)
|
||||
{
|
||||
|
@ -75,7 +75,7 @@ Json::Value ABI::generate(ContractDefinition const& _contractDef)
|
||||
abi.emplace(std::move(method));
|
||||
}
|
||||
FunctionDefinition const* constructor = _contractDef.constructor();
|
||||
if (constructor && constructor->visibility() >= Visibility::Public)
|
||||
if (constructor && !_contractDef.abstract())
|
||||
{
|
||||
FunctionType constrType(*constructor);
|
||||
FunctionType const* externalFunctionType = constrType.interfaceFunctionType();
|
||||
|
@ -47,8 +47,12 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef)
|
||||
{
|
||||
string const value = extractDoc(constructorDefinition->annotation().docTags, "notice");
|
||||
if (!value.empty())
|
||||
{
|
||||
// add the constructor, only if we have any documentation to add
|
||||
methods["constructor"] = Json::Value(value);
|
||||
Json::Value user;
|
||||
user["notice"] = Json::Value(value);
|
||||
methods["constructor"] = user;
|
||||
}
|
||||
}
|
||||
|
||||
string notice = extractDoc(_contractDef.annotation().docTags, "notice");
|
||||
|
@ -465,14 +465,6 @@ StateMutability Parser::parseStateMutability()
|
||||
case Token::Pure:
|
||||
stateMutability = StateMutability::Pure;
|
||||
break;
|
||||
case Token::Constant:
|
||||
stateMutability = StateMutability::View;
|
||||
parserError(
|
||||
7698_error,
|
||||
"The state mutability modifier \"constant\" was removed in version 0.5.0. "
|
||||
"Use \"view\" or \"pure\" instead."
|
||||
);
|
||||
break;
|
||||
default:
|
||||
solAssert(false, "Invalid state mutability specifier.");
|
||||
}
|
||||
@ -686,19 +678,13 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
RecursionGuard recursionGuard(*this);
|
||||
ASTNodeFactory nodeFactory = _lookAheadArrayType ?
|
||||
ASTNodeFactory(*this, _lookAheadArrayType) : ASTNodeFactory(*this);
|
||||
ASTPointer<TypeName> type;
|
||||
|
||||
ASTPointer<StructuredDocumentation> const documentation = parseStructuredDocumentation();
|
||||
if (_lookAheadArrayType)
|
||||
type = _lookAheadArrayType;
|
||||
else
|
||||
{
|
||||
type = parseTypeName(_options.allowVar);
|
||||
if (type != nullptr)
|
||||
nodeFactory.setEndPositionFromNode(type);
|
||||
}
|
||||
ASTPointer<TypeName> type = _lookAheadArrayType ? _lookAheadArrayType : parseTypeName();
|
||||
nodeFactory.setEndPositionFromNode(type);
|
||||
|
||||
if (!_options.isStateVariable && documentation != nullptr)
|
||||
parserWarning(2837_error, "Only state variables can have a docstring. This will be disallowed in 0.7.0.");
|
||||
parserError(2837_error, "Only state variables can have a docstring.");
|
||||
|
||||
if (dynamic_cast<FunctionTypeName*>(type.get()) && _options.isStateVariable && m_scanner->currentToken() == Token::LBrace)
|
||||
fatalParserError(
|
||||
@ -762,8 +748,6 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
{
|
||||
if (location != VariableDeclaration::Location::Unspecified)
|
||||
parserError(3548_error, "Location already specified.");
|
||||
else if (!type)
|
||||
parserError(7439_error, "Location specifier needs explicit type name.");
|
||||
else
|
||||
{
|
||||
switch (token)
|
||||
@ -790,10 +774,7 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(
|
||||
}
|
||||
|
||||
if (_options.allowEmptyName && m_scanner->currentToken() != Token::Identifier)
|
||||
{
|
||||
identifier = make_shared<ASTString>("");
|
||||
solAssert(!_options.allowVar, ""); // allowEmptyName && allowVar makes no sense
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeFactory.markEndPosition();
|
||||
@ -917,7 +898,7 @@ ASTPointer<UsingForDirective> Parser::parseUsingDirective()
|
||||
if (m_scanner->currentToken() == Token::Mul)
|
||||
m_scanner->next();
|
||||
else
|
||||
typeName = parseTypeName(false);
|
||||
typeName = parseTypeName();
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::Semicolon);
|
||||
return nodeFactory.createNode<UsingForDirective>(library, typeName);
|
||||
@ -980,7 +961,7 @@ ASTPointer<TypeName> Parser::parseTypeNameSuffix(ASTPointer<TypeName> type, ASTN
|
||||
return type;
|
||||
}
|
||||
|
||||
ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||
ASTPointer<TypeName> Parser::parseTypeName()
|
||||
{
|
||||
RecursionGuard recursionGuard(*this);
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
@ -998,7 +979,7 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||
auto stateMutability = elemTypeName.token() == Token::Address
|
||||
? optional<StateMutability>{StateMutability::NonPayable}
|
||||
: nullopt;
|
||||
if (TokenTraits::isStateMutabilitySpecifier(m_scanner->currentToken(), false))
|
||||
if (TokenTraits::isStateMutabilitySpecifier(m_scanner->currentToken()))
|
||||
{
|
||||
if (elemTypeName.token() == Token::Address)
|
||||
{
|
||||
@ -1013,12 +994,6 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||
}
|
||||
type = nodeFactory.createNode<ElementaryTypeName>(elemTypeName, stateMutability);
|
||||
}
|
||||
else if (token == Token::Var)
|
||||
{
|
||||
if (!_allowVar)
|
||||
parserError(7059_error, "Expected explicit type name.");
|
||||
m_scanner->next();
|
||||
}
|
||||
else if (token == Token::Function)
|
||||
type = parseFunctionType();
|
||||
else if (token == Token::Mapping)
|
||||
@ -1028,9 +1003,10 @@ ASTPointer<TypeName> Parser::parseTypeName(bool _allowVar)
|
||||
else
|
||||
fatalParserError(3546_error, "Expected type name");
|
||||
|
||||
if (type)
|
||||
// Parse "[...]" postfixes for arrays.
|
||||
type = parseTypeNameSuffix(type, nodeFactory);
|
||||
solAssert(type, "");
|
||||
// Parse "[...]" postfixes for arrays.
|
||||
type = parseTypeNameSuffix(type, nodeFactory);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
@ -1071,8 +1047,7 @@ ASTPointer<Mapping> Parser::parseMapping()
|
||||
else
|
||||
fatalParserError(1005_error, "Expected elementary type name or identifier for mapping key type");
|
||||
expectToken(Token::Arrow);
|
||||
bool const allowVar = false;
|
||||
ASTPointer<TypeName> valueType = parseTypeName(allowVar);
|
||||
ASTPointer<TypeName> valueType = parseTypeName();
|
||||
nodeFactory.markEndPosition();
|
||||
expectToken(Token::RParen);
|
||||
return nodeFactory.createNode<Mapping>(keyType, valueType);
|
||||
@ -1553,53 +1528,14 @@ ASTPointer<VariableDeclarationStatement> Parser::parseVariableDeclarationStateme
|
||||
ASTNodeFactory nodeFactory(*this);
|
||||
if (_lookAheadArrayType)
|
||||
nodeFactory.setLocation(_lookAheadArrayType->location());
|
||||
|
||||
VarDeclParserOptions options;
|
||||
options.allowLocationSpecifier = true;
|
||||
vector<ASTPointer<VariableDeclaration>> variables;
|
||||
variables.emplace_back(parseVariableDeclaration(options, _lookAheadArrayType));
|
||||
nodeFactory.setEndPositionFromNode(variables.back());
|
||||
|
||||
ASTPointer<Expression> value;
|
||||
if (
|
||||
!_lookAheadArrayType &&
|
||||
m_scanner->currentToken() == Token::Var &&
|
||||
m_scanner->peekNextToken() == Token::LParen
|
||||
)
|
||||
{
|
||||
// Parse `var (a, b, ,, c) = ...` into a single VariableDeclarationStatement with multiple variables.
|
||||
m_scanner->next();
|
||||
m_scanner->next();
|
||||
if (m_scanner->currentToken() != Token::RParen)
|
||||
while (true)
|
||||
{
|
||||
ASTPointer<VariableDeclaration> var;
|
||||
if (
|
||||
m_scanner->currentToken() != Token::Comma &&
|
||||
m_scanner->currentToken() != Token::RParen
|
||||
)
|
||||
{
|
||||
ASTNodeFactory varDeclNodeFactory(*this);
|
||||
varDeclNodeFactory.markEndPosition();
|
||||
ASTPointer<ASTString> name = expectIdentifierToken();
|
||||
var = varDeclNodeFactory.createNode<VariableDeclaration>(
|
||||
ASTPointer<TypeName>(),
|
||||
name,
|
||||
ASTPointer<Expression>(),
|
||||
Visibility::Default
|
||||
);
|
||||
}
|
||||
variables.push_back(var);
|
||||
if (m_scanner->currentToken() == Token::RParen)
|
||||
break;
|
||||
else
|
||||
expectToken(Token::Comma);
|
||||
}
|
||||
nodeFactory.markEndPosition();
|
||||
m_scanner->next();
|
||||
}
|
||||
else
|
||||
{
|
||||
VarDeclParserOptions options;
|
||||
options.allowVar = true;
|
||||
options.allowLocationSpecifier = true;
|
||||
variables.push_back(parseVariableDeclaration(options, _lookAheadArrayType));
|
||||
nodeFactory.setEndPositionFromNode(variables.back());
|
||||
}
|
||||
if (m_scanner->currentToken() == Token::Assign)
|
||||
{
|
||||
m_scanner->next();
|
||||
@ -1713,11 +1649,8 @@ ASTPointer<Expression> Parser::parseLeftHandSideExpression(
|
||||
else if (m_scanner->currentToken() == Token::New)
|
||||
{
|
||||
expectToken(Token::New);
|
||||
ASTPointer<TypeName> typeName(parseTypeName(false));
|
||||
if (typeName)
|
||||
nodeFactory.setEndPositionFromNode(typeName);
|
||||
else
|
||||
nodeFactory.markEndPosition();
|
||||
ASTPointer<TypeName> typeName(parseTypeName());
|
||||
nodeFactory.setEndPositionFromNode(typeName);
|
||||
expression = nodeFactory.createNode<NewExpression>(typeName);
|
||||
}
|
||||
else if (m_scanner->currentToken() == Token::Payable)
|
||||
@ -1826,16 +1759,11 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
|
||||
expression = nodeFactory.createNode<Literal>(token, getLiteralAndAdvance());
|
||||
break;
|
||||
case Token::Number:
|
||||
if (
|
||||
(m_scanner->peekNextToken() == Token::Identifier && m_scanner->peekLiteral() == "gwei") ||
|
||||
TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken())
|
||||
)
|
||||
if (TokenTraits::isEtherSubdenomination(m_scanner->peekNextToken()))
|
||||
{
|
||||
ASTPointer<ASTString> literal = getLiteralAndAdvance();
|
||||
nodeFactory.markEndPosition();
|
||||
Token actualToken = m_scanner->currentToken() == Token::Identifier ? Token::SubGwei : m_scanner->currentToken();
|
||||
|
||||
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(actualToken);
|
||||
Literal::SubDenomination subdenomination = static_cast<Literal::SubDenomination>(m_scanner->currentToken());
|
||||
m_scanner->next();
|
||||
expression = nodeFactory.createNode<Literal>(token, literal, subdenomination);
|
||||
}
|
||||
@ -2062,7 +1990,7 @@ Parser::LookAheadInfo Parser::peekStatementType() const
|
||||
Token token(m_scanner->currentToken());
|
||||
bool mightBeTypeName = (TokenTraits::isElementaryTypeName(token) || token == Token::Identifier);
|
||||
|
||||
if (token == Token::Mapping || token == Token::Function || token == Token::Var)
|
||||
if (token == Token::Mapping || token == Token::Function)
|
||||
return LookAheadInfo::VariableDeclaration;
|
||||
if (mightBeTypeName)
|
||||
{
|
||||
@ -2071,7 +1999,7 @@ Parser::LookAheadInfo Parser::peekStatementType() const
|
||||
// kind of statement. This means, for example, that we do not allow type expressions of the form
|
||||
// ``address payable;``.
|
||||
// If we want to change this in the future, we need to consider another scanner token here.
|
||||
if (TokenTraits::isElementaryTypeName(token) && TokenTraits::isStateMutabilitySpecifier(next, false))
|
||||
if (TokenTraits::isElementaryTypeName(token) && TokenTraits::isStateMutabilitySpecifier(next))
|
||||
return LookAheadInfo::VariableDeclaration;
|
||||
if (next == Token::Identifier || TokenTraits::isLocationSpecifier(next))
|
||||
return LookAheadInfo::VariableDeclaration;
|
||||
|
@ -58,7 +58,6 @@ private:
|
||||
// https://stackoverflow.com/questions/17430377
|
||||
VarDeclParserOptions() {}
|
||||
|
||||
bool allowVar = false;
|
||||
bool isStateVariable = false;
|
||||
bool allowIndexed = false;
|
||||
bool allowEmptyName = false;
|
||||
@ -108,7 +107,7 @@ private:
|
||||
ASTPointer<Identifier> parseIdentifier();
|
||||
ASTPointer<UserDefinedTypeName> parseUserDefinedTypeName();
|
||||
ASTPointer<TypeName> parseTypeNameSuffix(ASTPointer<TypeName> type, ASTNodeFactory& nodeFactory);
|
||||
ASTPointer<TypeName> parseTypeName(bool _allowVar);
|
||||
ASTPointer<TypeName> parseTypeName();
|
||||
ASTPointer<FunctionTypeName> parseFunctionType();
|
||||
ASTPointer<Mapping> parseMapping();
|
||||
ASTPointer<ParameterList> parseParameterList(
|
||||
|
@ -88,8 +88,31 @@ bool parse(Json::CharReaderBuilder& _builder, string const& _input, Json::Value&
|
||||
return reader->parse(_input.c_str(), _input.c_str() + _input.length(), &_json, _errs);
|
||||
}
|
||||
|
||||
/// Takes a JSON value (@ _json) and removes all its members with value 'null' recursively.
|
||||
void removeNullMembersHelper(Json::Value& _json)
|
||||
{
|
||||
if (_json.type() == Json::ValueType::arrayValue)
|
||||
for (auto& child: _json)
|
||||
removeNullMembersHelper(child);
|
||||
else if (_json.type() == Json::ValueType::objectValue)
|
||||
for (auto const& key: _json.getMemberNames())
|
||||
{
|
||||
Json::Value& value = _json[key];
|
||||
if (value.isNull())
|
||||
_json.removeMember(key);
|
||||
else
|
||||
removeNullMembersHelper(value);
|
||||
}
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
Json::Value removeNullMembers(Json::Value _json)
|
||||
{
|
||||
removeNullMembersHelper(_json);
|
||||
return _json;
|
||||
}
|
||||
|
||||
string jsonPrettyPrint(Json::Value const& _input)
|
||||
{
|
||||
static map<string, Json::Value> settings{{"indentation", " "}, {"enableYAMLCompatibility", true}};
|
||||
|
@ -29,6 +29,9 @@
|
||||
|
||||
namespace solidity::util {
|
||||
|
||||
/// Removes members with null value recursively from (@a _json).
|
||||
Json::Value removeNullMembers(Json::Value _json);
|
||||
|
||||
/// Serialise the JSON object (@a _input) with indentation
|
||||
std::string jsonPrettyPrint(Json::Value const& _input);
|
||||
|
||||
|
@ -209,7 +209,10 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
|
||||
m_currentScope->insideFunction()
|
||||
);
|
||||
for (auto const& variable: _varDecl.variables)
|
||||
{
|
||||
expectValidIdentifier(variable.name, variable.location);
|
||||
expectValidType(variable.type, variable.location);
|
||||
}
|
||||
|
||||
if (_varDecl.value)
|
||||
{
|
||||
@ -249,11 +252,13 @@ void AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
|
||||
void AsmAnalyzer::operator()(FunctionDefinition const& _funDef)
|
||||
{
|
||||
yulAssert(!_funDef.name.empty(), "");
|
||||
expectValidIdentifier(_funDef.name, _funDef.location);
|
||||
Block const* virtualBlock = m_info.virtualBlocks.at(&_funDef).get();
|
||||
yulAssert(virtualBlock, "");
|
||||
Scope& varScope = scope(virtualBlock);
|
||||
for (auto const& var: _funDef.parameters + _funDef.returnVariables)
|
||||
{
|
||||
expectValidIdentifier(var.name, var.location);
|
||||
expectValidType(var.type, var.location);
|
||||
m_activeVariables.insert(&std::get<Scope::Variable>(varScope.identifiers.at(var.name)));
|
||||
}
|
||||
@ -529,6 +534,26 @@ Scope& AsmAnalyzer::scope(Block const* _block)
|
||||
return *scopePtr;
|
||||
}
|
||||
|
||||
void AsmAnalyzer::expectValidIdentifier(YulString _identifier, SourceLocation const& _location)
|
||||
{
|
||||
// NOTE: the leading dot case is handled by the parser not allowing it.
|
||||
|
||||
if (boost::ends_with(_identifier.str(), "."))
|
||||
m_errorReporter.syntaxError(
|
||||
3384_error,
|
||||
_location,
|
||||
"\"" + _identifier.str() + "\" is not a valid identifier (ends with a dot)."
|
||||
);
|
||||
|
||||
if (_identifier.str().find("..") != std::string::npos)
|
||||
m_errorReporter.syntaxError(
|
||||
7771_error,
|
||||
_location,
|
||||
"\"" + _identifier.str() + "\" is not a valid identifier (contains consecutive dots)."
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void AsmAnalyzer::expectValidType(YulString _type, SourceLocation const& _location)
|
||||
{
|
||||
if (!m_dialect.types.count(_type))
|
||||
@ -611,13 +636,15 @@ bool AsmAnalyzer::validateInstructions(evmasm::Instruction _instr, SourceLocatio
|
||||
errorForVM(7110_error, "only available for Constantinople-compatible");
|
||||
else if (_instr == evmasm::Instruction::CHAINID && !m_evmVersion.hasChainID())
|
||||
errorForVM(1561_error, "only available for Istanbul-compatible");
|
||||
else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
|
||||
errorForVM(7721_error, "only available for Istanbul-compatible");
|
||||
else if (_instr == evmasm::Instruction::PC)
|
||||
m_errorReporter.warning(
|
||||
m_errorReporter.error(
|
||||
2450_error,
|
||||
Error::Type::SyntaxError,
|
||||
_location,
|
||||
"The \"" +
|
||||
boost::to_lower_copy(instructionInfo(_instr).name) +
|
||||
"\" instruction is deprecated and will be removed in the next breaking release."
|
||||
"PC instruction is a low-level EVM feature. "
|
||||
"Because of that PC is disallowed in strict assembly."
|
||||
);
|
||||
else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
|
||||
errorForVM(3672_error, "only available for Istanbul-compatible");
|
||||
|
@ -108,6 +108,7 @@ private:
|
||||
void checkAssignment(Identifier const& _variable, YulString _valueType);
|
||||
|
||||
Scope& scope(Block const* _block);
|
||||
void expectValidIdentifier(YulString _identifier, langutil::SourceLocation const& _location);
|
||||
void expectValidType(YulString _type, langutil::SourceLocation const& _location);
|
||||
void expectType(YulString _expectedType, YulString _givenType, langutil::SourceLocation const& _location);
|
||||
|
||||
|
@ -1024,11 +1024,6 @@ function sstore(x1, x2, x3, x4, y1, y2, y3, y4) {
|
||||
eth.storageStore(0:i32, 32:i32)
|
||||
}
|
||||
|
||||
// Needed?
|
||||
function pc() -> z1, z2, z3, z4 {
|
||||
// TODO implement
|
||||
unreachable()
|
||||
}
|
||||
function gas() -> z1, z2, z3, z4 {
|
||||
z4 := eth.getGasLeft()
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ void CommandLineInterface::handleABI(string const& _contract)
|
||||
if (!m_args.count(g_argAbi))
|
||||
return;
|
||||
|
||||
string data = jsonCompactPrint(m_compiler->contractABI(_contract));
|
||||
string data = jsonCompactPrint(removeNullMembers(m_compiler->contractABI(_contract)));
|
||||
if (m_args.count(g_argOutputDir))
|
||||
createFile(m_compiler->filesystemFriendlyName(_contract) + ".abi", data);
|
||||
else
|
||||
@ -454,7 +454,7 @@ void CommandLineInterface::handleStorageLayout(string const& _contract)
|
||||
if (!m_args.count(g_argStorageLayout))
|
||||
return;
|
||||
|
||||
string data = jsonCompactPrint(m_compiler->storageLayout(_contract));
|
||||
string data = jsonCompactPrint(removeNullMembers(m_compiler->storageLayout(_contract)));
|
||||
if (m_args.count(g_argOutputDir))
|
||||
createFile(m_compiler->filesystemFriendlyName(_contract) + "_storage.json", data);
|
||||
else
|
||||
@ -483,9 +483,11 @@ void CommandLineInterface::handleNatspec(bool _natspecDev, string const& _contra
|
||||
if (m_args.count(argName))
|
||||
{
|
||||
std::string output = jsonPrettyPrint(
|
||||
_natspecDev ?
|
||||
m_compiler->natspecDev(_contract) :
|
||||
m_compiler->natspecUser(_contract)
|
||||
removeNullMembers(
|
||||
_natspecDev ?
|
||||
m_compiler->natspecDev(_contract) :
|
||||
m_compiler->natspecUser(_contract)
|
||||
)
|
||||
);
|
||||
|
||||
if (m_args.count(g_argOutputDir))
|
||||
@ -1561,7 +1563,8 @@ void CommandLineInterface::handleCombinedJSON()
|
||||
}
|
||||
}
|
||||
|
||||
string json = m_args.count(g_argPrettyJson) ? jsonPrettyPrint(output) : jsonCompactPrint(output);
|
||||
string json = m_args.count(g_argPrettyJson) ? jsonPrettyPrint(removeNullMembers(std::move(output))) :
|
||||
jsonCompactPrint(removeNullMembers(std::move(output)));
|
||||
|
||||
if (m_args.count(g_argOutputDir))
|
||||
createJson("combined", json);
|
||||
@ -1877,7 +1880,7 @@ void CommandLineInterface::outputCompilationResults()
|
||||
{
|
||||
string ret;
|
||||
if (m_args.count(g_argAsmJson))
|
||||
ret = jsonPrettyPrint(m_compiler->assemblyJSON(contract));
|
||||
ret = jsonPrettyPrint(removeNullMembers(m_compiler->assemblyJSON(contract)));
|
||||
else
|
||||
ret = m_compiler->assemblyString(contract, m_sourceCodes);
|
||||
|
||||
|
@ -46,13 +46,9 @@ using rational = boost::rational<bigint>;
|
||||
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
|
||||
using Address = util::h160;
|
||||
|
||||
// The various denominations; here for ease of use where needed within code.
|
||||
static const u256 wei = 1;
|
||||
static const u256 shannon = u256("1000000000");
|
||||
static const u256 gwei = shannon;
|
||||
static const u256 szabo = shannon * 1000;
|
||||
static const u256 finney = szabo * 1000;
|
||||
static const u256 ether = finney * 1000;
|
||||
// The ether and gwei denominations; here for ease of use where needed within code.
|
||||
static const u256 gwei = u256(1) << 9;
|
||||
static const u256 ether = u256(1) << 18;
|
||||
|
||||
class ExecutionFramework
|
||||
{
|
||||
@ -288,7 +284,7 @@ protected:
|
||||
bool m_transactionSuccessful = true;
|
||||
Address m_sender = account(0);
|
||||
Address m_contractAddress;
|
||||
u256 const m_gasPrice = 100 * szabo;
|
||||
u256 const m_gasPrice = 10 * gwei;
|
||||
u256 const m_gas = 100000000;
|
||||
bytes m_output;
|
||||
u256 m_gasUsed;
|
||||
|
@ -2,7 +2,7 @@
|
||||
pragma solidity >=0.6.0;
|
||||
|
||||
contract C {
|
||||
constructor() public {}
|
||||
constructor() {}
|
||||
}
|
||||
contract D is C {
|
||||
}
|
@ -5,10 +5,10 @@ Warning: Source file does not specify required compiler version!
|
||||
--> message_format_utf8/input.sol
|
||||
|
||||
Warning: Statement has no effect.
|
||||
--> message_format_utf8/input.sol:2:58:
|
||||
--> message_format_utf8/input.sol:2:51:
|
||||
|
|
||||
2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
|
||||
| ^^^^^^^^^^^^
|
||||
2 | /* ©©©©ᄅ©©©©© 2017 */ constructor () { "©©©©ᄅ©©©©©" ; }
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
Warning: Statement has no effect.
|
||||
--> message_format_utf8/input.sol:6:25:
|
||||
|
@ -1,5 +1,5 @@
|
||||
contract Foo {
|
||||
/* ©©©©ᄅ©©©©© 2017 */ constructor () public { "©©©©ᄅ©©©©©" ; }
|
||||
/* ©©©©ᄅ©©©©© 2017 */ constructor () { "©©©©ᄅ©©©©©" ; }
|
||||
|
||||
function f() public pure {
|
||||
|
||||
|
@ -3,7 +3,7 @@ pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
constructor() public payable
|
||||
constructor() payable
|
||||
{
|
||||
int a;
|
||||
|
||||
|
@ -1,69 +1,69 @@
|
||||
|
||||
======= optimizer_user_yul/input.sol:C =======
|
||||
EVM assembly:
|
||||
/* "optimizer_user_yul/input.sol":60:525 contract C... */
|
||||
/* "optimizer_user_yul/input.sol":60:518 contract C... */
|
||||
mstore(0x40, 0x80)
|
||||
/* "optimizer_user_yul/input.sol":108:113 int a */
|
||||
/* "optimizer_user_yul/input.sol":101:106 int a */
|
||||
0x00
|
||||
/* "optimizer_user_yul/input.sol":188:197 let x,y,z */
|
||||
/* "optimizer_user_yul/input.sol":181:190 let x,y,z */
|
||||
dup1
|
||||
0x00
|
||||
dup1
|
||||
/* "optimizer_user_yul/input.sol":212:213 1 */
|
||||
/* "optimizer_user_yul/input.sol":205:206 1 */
|
||||
0x01
|
||||
/* "optimizer_user_yul/input.sol":209:210 0 */
|
||||
/* "optimizer_user_yul/input.sol":202:203 0 */
|
||||
0x00
|
||||
/* "optimizer_user_yul/input.sol":202:214 sstore(0, 1) */
|
||||
/* "optimizer_user_yul/input.sol":195:207 sstore(0, 1) */
|
||||
sstore
|
||||
/* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */
|
||||
/* "optimizer_user_yul/input.sol":212:258 for { } sload(4) { } {... */
|
||||
tag_3:
|
||||
/* "optimizer_user_yul/input.sol":233:234 4 */
|
||||
/* "optimizer_user_yul/input.sol":226:227 4 */
|
||||
0x04
|
||||
/* "optimizer_user_yul/input.sol":227:235 sload(4) */
|
||||
/* "optimizer_user_yul/input.sol":220:228 sload(4) */
|
||||
sload
|
||||
/* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */
|
||||
/* "optimizer_user_yul/input.sol":212:258 for { } sload(4) { } {... */
|
||||
iszero
|
||||
tag_5
|
||||
jumpi
|
||||
pop
|
||||
/* "optimizer_user_yul/input.sol":251:260 exp(x, y) */
|
||||
/* "optimizer_user_yul/input.sol":244:253 exp(x, y) */
|
||||
dup1
|
||||
dup3
|
||||
exp
|
||||
/* "optimizer_user_yul/input.sol":219:265 for { } sload(4) { } {... */
|
||||
/* "optimizer_user_yul/input.sol":212:258 for { } sload(4) { } {... */
|
||||
jump(tag_3)
|
||||
tag_5:
|
||||
/* "optimizer_user_yul/input.sol":223:226 { } */
|
||||
/* "optimizer_user_yul/input.sol":216:219 { } */
|
||||
pop
|
||||
pop
|
||||
pop
|
||||
/* "optimizer_user_yul/input.sol":275:276 2 */
|
||||
/* "optimizer_user_yul/input.sol":268:269 2 */
|
||||
0x02
|
||||
/* "optimizer_user_yul/input.sol":270:276 a := 2 */
|
||||
/* "optimizer_user_yul/input.sol":263:269 a := 2 */
|
||||
swap1
|
||||
pop
|
||||
/* "optimizer_user_yul/input.sol":376:377 3 */
|
||||
/* "optimizer_user_yul/input.sol":369:370 3 */
|
||||
0x03
|
||||
/* "optimizer_user_yul/input.sol":373:374 2 */
|
||||
/* "optimizer_user_yul/input.sol":366:367 2 */
|
||||
0x02
|
||||
/* "optimizer_user_yul/input.sol":366:378 sstore(2, 3) */
|
||||
/* "optimizer_user_yul/input.sol":359:371 sstore(2, 3) */
|
||||
sstore
|
||||
/* "optimizer_user_yul/input.sol":383:516 for { } sload(5) { } {... */
|
||||
/* "optimizer_user_yul/input.sol":376:509 for { } sload(5) { } {... */
|
||||
tag_6:
|
||||
/* "optimizer_user_yul/input.sol":397:398 5 */
|
||||
/* "optimizer_user_yul/input.sol":390:391 5 */
|
||||
0x05
|
||||
/* "optimizer_user_yul/input.sol":391:399 sload(5) */
|
||||
/* "optimizer_user_yul/input.sol":384:392 sload(5) */
|
||||
sload
|
||||
tag_9
|
||||
jumpi
|
||||
jump(tag_8)
|
||||
tag_9:
|
||||
/* "optimizer_user_yul/input.sol":383:516 for { } sload(5) { } {... */
|
||||
/* "optimizer_user_yul/input.sol":376:509 for { } sload(5) { } {... */
|
||||
jump(tag_6)
|
||||
tag_8:
|
||||
/* "optimizer_user_yul/input.sol":347:520 {... */
|
||||
/* "optimizer_user_yul/input.sol":340:513 {... */
|
||||
pop
|
||||
/* "optimizer_user_yul/input.sol":60:525 contract C... */
|
||||
/* "optimizer_user_yul/input.sol":60:518 contract C... */
|
||||
dataSize(sub_0)
|
||||
dup1
|
||||
dataOffset(sub_0)
|
||||
@ -74,7 +74,7 @@ tag_8:
|
||||
stop
|
||||
|
||||
sub_0: assembly {
|
||||
/* "optimizer_user_yul/input.sol":60:525 contract C... */
|
||||
/* "optimizer_user_yul/input.sol":60:518 contract C... */
|
||||
mstore(0x40, 0x80)
|
||||
0x00
|
||||
dup1
|
||||
|
@ -2,7 +2,7 @@
|
||||
pragma solidity >=0.0.0;
|
||||
|
||||
contract Error1 {
|
||||
constructor() public {
|
||||
constructor() {
|
||||
balances[tx.origin] = ; // missing RHS.
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,6 @@ JSON AST:
|
||||
null
|
||||
],
|
||||
"contractKind": "contract",
|
||||
"documentation": null,
|
||||
"fullyImplemented": true,
|
||||
"linearizedBaseContracts":
|
||||
[
|
||||
@ -59,7 +58,6 @@ JSON AST:
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"documentation": null,
|
||||
"implemented": true,
|
||||
"isConstructor": true,
|
||||
"kind": "constructor",
|
||||
@ -68,7 +66,6 @@ JSON AST:
|
||||
null
|
||||
],
|
||||
"name": "",
|
||||
"overrides": null,
|
||||
"scope": 18,
|
||||
"stateMutability": "nonpayable",
|
||||
"virtual": false,
|
||||
@ -100,7 +97,7 @@ JSON AST:
|
||||
"children": [],
|
||||
"id": 3,
|
||||
"name": "ParameterList",
|
||||
"src": "103:0:0"
|
||||
"src": "96:0:0"
|
||||
},
|
||||
{
|
||||
"attributes":
|
||||
@ -113,17 +110,16 @@ JSON AST:
|
||||
"children": [],
|
||||
"id": 8,
|
||||
"name": "Block",
|
||||
"src": "103:49:0"
|
||||
"src": "96:49:0"
|
||||
}
|
||||
],
|
||||
"id": 9,
|
||||
"name": "FunctionDefinition",
|
||||
"src": "82:70:0"
|
||||
"src": "82:63:0"
|
||||
},
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"documentation": null,
|
||||
"functionSelector": "af11c34c",
|
||||
"implemented": true,
|
||||
"isConstructor": false,
|
||||
@ -133,7 +129,6 @@ JSON AST:
|
||||
null
|
||||
],
|
||||
"name": "five",
|
||||
"overrides": null,
|
||||
"scope": 18,
|
||||
"stateMutability": "view",
|
||||
"virtual": false,
|
||||
@ -152,7 +147,7 @@ JSON AST:
|
||||
"children": [],
|
||||
"id": 10,
|
||||
"name": "ParameterList",
|
||||
"src": "418:2:0"
|
||||
"src": "411:2:0"
|
||||
},
|
||||
{
|
||||
"children":
|
||||
@ -163,12 +158,10 @@ JSON AST:
|
||||
"constant": false,
|
||||
"mutability": "mutable",
|
||||
"name": "",
|
||||
"overrides": null,
|
||||
"scope": 17,
|
||||
"stateVariable": false,
|
||||
"storageLocation": "default",
|
||||
"type": "uint256",
|
||||
"value": null,
|
||||
"visibility": "internal"
|
||||
},
|
||||
"children":
|
||||
@ -181,17 +174,17 @@ JSON AST:
|
||||
},
|
||||
"id": 11,
|
||||
"name": "ElementaryTypeName",
|
||||
"src": "441:4:0"
|
||||
"src": "434:4:0"
|
||||
}
|
||||
],
|
||||
"id": 12,
|
||||
"name": "VariableDeclaration",
|
||||
"src": "441:4:0"
|
||||
"src": "434:4:0"
|
||||
}
|
||||
],
|
||||
"id": 13,
|
||||
"name": "ParameterList",
|
||||
"src": "440:6:0"
|
||||
"src": "433:6:0"
|
||||
},
|
||||
{
|
||||
"children":
|
||||
@ -206,43 +199,41 @@ JSON AST:
|
||||
{
|
||||
"attributes":
|
||||
{
|
||||
"argumentTypes": null,
|
||||
"hexvalue": "35",
|
||||
"isConstant": false,
|
||||
"isLValue": false,
|
||||
"isPure": true,
|
||||
"lValueRequested": false,
|
||||
"subdenomination": null,
|
||||
"token": "number",
|
||||
"type": "int_const 5",
|
||||
"value": "5"
|
||||
},
|
||||
"id": 14,
|
||||
"name": "Literal",
|
||||
"src": "460:1:0"
|
||||
"src": "453:1:0"
|
||||
}
|
||||
],
|
||||
"id": 15,
|
||||
"name": "Return",
|
||||
"src": "453:8:0"
|
||||
"src": "446:8:0"
|
||||
}
|
||||
],
|
||||
"id": 16,
|
||||
"name": "Block",
|
||||
"src": "447:19:0"
|
||||
"src": "440:19:0"
|
||||
}
|
||||
],
|
||||
"id": 17,
|
||||
"name": "FunctionDefinition",
|
||||
"src": "405:61:0"
|
||||
"src": "398:61:0"
|
||||
}
|
||||
],
|
||||
"id": 18,
|
||||
"name": "ContractDefinition",
|
||||
"src": "62:406:0"
|
||||
"src": "62:399:0"
|
||||
}
|
||||
],
|
||||
"id": 19,
|
||||
"name": "SourceUnit",
|
||||
"src": "36:433:0"
|
||||
"src": "36:426:0"
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}"
|
||||
"content": "//SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract A { constructor(uint) {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
{"errors":[{"component":"general","errorCode":"3364","formattedMessage":"A:2:112: DeclarationError: Base constructor arguments given twice.
|
||||
pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
||||
^-------------------^
|
||||
A:2:81: First constructor call is here:
|
||||
pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
||||
^--^
|
||||
A:2:104: Second constructor call is here:
|
||||
pragma solidity >=0.0; contract A { constructor(uint) public {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
||||
^--^
|
||||
","message":"Base constructor arguments given twice.","secondarySourceLocations":[{"end":119,"file":"A","message":"First constructor call is here:","start":115},{"end":142,"file":"A","message":"Second constructor call is here:","start":138}],"severity":"error","sourceLocation":{"end":167,"file":"A","start":146},"type":"DeclarationError"}],"sources":{}}
|
||||
{"errors":[{"component":"general","errorCode":"3364","formattedMessage":"A:2:105: DeclarationError: Base constructor arguments given twice.
|
||||
pragma solidity >=0.0; contract A { constructor(uint) {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
||||
^-------------------^
|
||||
A:2:74: First constructor call is here:
|
||||
pragma solidity >=0.0; contract A { constructor(uint) {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
||||
^--^
|
||||
A:2:97: Second constructor call is here:
|
||||
pragma solidity >=0.0; contract A { constructor(uint) {} } contract B is A(2) { } contract C is A(3) {} contract D is B, C {}
|
||||
^--^
|
||||
","message":"Base constructor arguments given twice.","secondarySourceLocations":[{"end":112,"file":"A","message":"First constructor call is here:","start":108},{"end":135,"file":"A","message":"Second constructor call is here:","start":131}],"severity":"error","sourceLocation":{"end":160,"file":"A","start":139},"type":"DeclarationError"}],"sources":{}}
|
||||
|
@ -3,5 +3,5 @@ pragma solidity >=0.0;
|
||||
|
||||
contract C
|
||||
{
|
||||
constructor() public {}
|
||||
constructor() {}
|
||||
}
|
||||
|
@ -104,7 +104,6 @@ contract MultiSigWallet {
|
||||
/// @param _owners List of initial owners.
|
||||
/// @param _required Number of required confirmations.
|
||||
constructor(address[] memory _owners, uint _required)
|
||||
public
|
||||
validRequirement(_owners.length, _required)
|
||||
{
|
||||
for (uint i=0; i<_owners.length; i++) {
|
||||
@ -227,7 +226,7 @@ contract MultiSigWallet {
|
||||
{
|
||||
if (isConfirmed(transactionId)) {
|
||||
Transaction storage tx = transactions[transactionId];
|
||||
(tx.executed,) = tx.destination.call.value(tx.value)(tx.data);
|
||||
(tx.executed,) = tx.destination.call{value: tx.value}(tx.data);
|
||||
if (tx.executed)
|
||||
emit Execution(transactionId);
|
||||
else
|
||||
|
@ -20,7 +20,6 @@ contract MultiSigWalletWithDailyLimit is MultiSigWallet {
|
||||
/// @param _required Number of required confirmations.
|
||||
/// @param _dailyLimit Amount in wei, which can be withdrawn without confirmations on a daily basis.
|
||||
constructor(address[] memory _owners, uint _required, uint _dailyLimit)
|
||||
public
|
||||
MultiSigWallet(_owners, _required)
|
||||
{
|
||||
dailyLimit = _dailyLimit;
|
||||
@ -48,7 +47,7 @@ contract MultiSigWalletWithDailyLimit is MultiSigWallet {
|
||||
if (confirmed || tx.data.length == 0 && isUnderLimit(tx.value)) {
|
||||
if (!confirmed)
|
||||
spentToday += tx.value;
|
||||
(tx.executed,) = tx.destination.call.value(tx.value)(tx.data);
|
||||
(tx.executed,) = tx.destination.call{value: tx.value}(tx.data);
|
||||
if (tx.executed)
|
||||
emit Execution(transactionId);
|
||||
else {
|
||||
@ -69,8 +68,8 @@ contract MultiSigWalletWithDailyLimit is MultiSigWallet {
|
||||
internal
|
||||
returns (bool)
|
||||
{
|
||||
if (now > lastDay + 24 hours) {
|
||||
lastDay = now;
|
||||
if (block.timestamp > lastDay + 24 hours) {
|
||||
lastDay = block.timestamp;
|
||||
spentToday = 0;
|
||||
}
|
||||
if (spentToday + amount > dailyLimit || spentToday + amount < spentToday)
|
||||
@ -88,7 +87,7 @@ contract MultiSigWalletWithDailyLimit is MultiSigWallet {
|
||||
view
|
||||
returns (uint)
|
||||
{
|
||||
if (now > lastDay + 24 hours)
|
||||
if (block.timestamp > lastDay + 24 hours)
|
||||
return dailyLimit;
|
||||
if (dailyLimit < spentToday)
|
||||
return 0;
|
||||
|
@ -50,7 +50,7 @@ contract ico is safeMath {
|
||||
uint256 public totalMint;
|
||||
uint256 public totalPremiumMint;
|
||||
|
||||
constructor(address payable foundation, address priceSet, uint256 exchangeRate, uint256 startBlockNum, address[] memory genesisAddr, uint256[] memory genesisValue) public {
|
||||
constructor(address payable foundation, address priceSet, uint256 exchangeRate, uint256 startBlockNum, address[] memory genesisAddr, uint256[] memory genesisValue) {
|
||||
/*
|
||||
Installation function.
|
||||
|
||||
|
@ -36,7 +36,7 @@ contract moduleHandler is multiOwner, announcementTypes {
|
||||
uint256 debugModeUntil = block.number + 1000000;
|
||||
|
||||
|
||||
constructor(address[] memory newOwners) multiOwner(newOwners) public {}
|
||||
constructor(address[] memory newOwners) multiOwner(newOwners) {}
|
||||
function load(address payable foundation, bool forReplace, address payable Token, address payable Premium, address payable Publisher, address payable Schelling, address payable Provider) public {
|
||||
/*
|
||||
Loading modulest to ModuleHandler.
|
||||
|
@ -12,7 +12,7 @@ contract multiOwner is safeMath {
|
||||
/*
|
||||
Constructor
|
||||
*/
|
||||
constructor(address[] memory newOwners) public {
|
||||
constructor(address[] memory newOwners) {
|
||||
for ( uint256 a=0 ; a<newOwners.length ; a++ ) {
|
||||
_addOwner(newOwners[a]);
|
||||
}
|
||||
|
@ -11,6 +11,12 @@ contract thirdPartyPContractAbstract {
|
||||
|
||||
contract ptokenDB is tokenDB {}
|
||||
|
||||
/**
|
||||
*
|
||||
* @title Corion Platform Premium Token
|
||||
* @author iFA @ Corion Platform
|
||||
*
|
||||
*/
|
||||
contract premium is module, safeMath {
|
||||
function replaceModule(address payable addr) external override returns (bool success) {
|
||||
require( super.isModuleHandler(msg.sender) );
|
||||
@ -23,12 +29,6 @@ contract premium is module, safeMath {
|
||||
require( _success && _active );
|
||||
_;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @title Corion Platform Premium Token
|
||||
* @author iFA @ Corion Platform
|
||||
*
|
||||
*/
|
||||
|
||||
string public name = "Corion Premium";
|
||||
string public symbol = "CORP";
|
||||
@ -40,7 +40,7 @@ contract premium is module, safeMath {
|
||||
|
||||
mapping(address => bool) public genesis;
|
||||
|
||||
constructor(bool forReplace, address payable moduleHandler, address dbAddress, address icoContractAddr, address[] memory genesisAddr, uint256[] memory genesisValue) public {
|
||||
constructor(bool forReplace, address payable moduleHandler, address dbAddress, address icoContractAddr, address[] memory genesisAddr, uint256[] memory genesisValue) {
|
||||
/*
|
||||
Setup function.
|
||||
If an ICOaddress is defined then the balance of the genesis addresses will be set as well.
|
||||
|
@ -118,7 +118,7 @@ contract provider is module, safeMath, announcementTypes {
|
||||
|
||||
uint256 private currentSchellingRound = 1;
|
||||
|
||||
constructor(address payable _moduleHandler) public {
|
||||
constructor(address payable _moduleHandler) {
|
||||
/*
|
||||
Install function.
|
||||
|
||||
@ -256,7 +256,7 @@ contract provider is module, safeMath, announcementTypes {
|
||||
providers[msg.sender].data[currHeight].country = country;
|
||||
providers[msg.sender].data[currHeight].info = info;
|
||||
providers[msg.sender].data[currHeight].currentRate = rate;
|
||||
providers[msg.sender].data[currHeight].create = now;
|
||||
providers[msg.sender].data[currHeight].create = block.timestamp;
|
||||
providers[msg.sender].data[currHeight].lastPaidRate = rate;
|
||||
providers[msg.sender].data[currHeight].priv = priv;
|
||||
providers[msg.sender].data[currHeight].lastSupplyID = currentSchellingRound;
|
||||
@ -436,7 +436,7 @@ contract provider is module, safeMath, announcementTypes {
|
||||
clients[msg.sender].lastSupplyID = currentSchellingRound;
|
||||
clients[msg.sender].paidUpTo = currentSchellingRound;
|
||||
clients[msg.sender].lastRate = providers[provider].data[currHeight].currentRate;
|
||||
clients[msg.sender].providerConnected = now;
|
||||
clients[msg.sender].providerConnected = block.timestamp;
|
||||
emit ENewClient(msg.sender, provider, currHeight, bal);
|
||||
}
|
||||
function partProvider() isReady external {
|
||||
|
@ -61,7 +61,7 @@ contract publisher is announcementTypes, module, safeMath {
|
||||
|
||||
mapping (address => uint256[]) public opponents;
|
||||
|
||||
constructor(address payable moduleHandler) public {
|
||||
constructor(address payable moduleHandler) {
|
||||
/*
|
||||
Installation function. The installer will be registered in the admin list automatically
|
||||
|
||||
|
@ -45,7 +45,7 @@ contract schellingDB is safeMath, schellingVars {
|
||||
/*
|
||||
Constructor
|
||||
*/
|
||||
constructor() public {
|
||||
constructor() {
|
||||
rounds.push();
|
||||
rounds.push();
|
||||
rounds[0].blockHeight = block.number;
|
||||
@ -249,7 +249,7 @@ contract schelling is module, announcementTypes, schellingVars {
|
||||
bytes1 public belowChar = 0x30;
|
||||
schellingDB private db;
|
||||
|
||||
constructor(address payable _moduleHandler, address _db, bool _forReplace) public {
|
||||
constructor(address payable _moduleHandler, address _db, bool _forReplace) {
|
||||
/*
|
||||
Installation function.
|
||||
|
||||
|
@ -11,6 +11,12 @@ contract thirdPartyContractAbstract {
|
||||
function approvedCorionToken(address, uint256, bytes calldata) external returns (bool) {}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @title Corion Platform Token
|
||||
* @author iFA @ Corion Platform
|
||||
*
|
||||
*/
|
||||
contract token is safeMath, module, announcementTypes {
|
||||
/*
|
||||
module callbacks
|
||||
@ -26,12 +32,7 @@ contract token is safeMath, module, announcementTypes {
|
||||
require( _success && _active );
|
||||
_;
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @title Corion Platform Token
|
||||
* @author iFA @ Corion Platform
|
||||
*
|
||||
*/
|
||||
|
||||
string public name = "Corion";
|
||||
string public symbol = "COR";
|
||||
uint8 public decimals = 6;
|
||||
@ -48,7 +49,7 @@ contract token is safeMath, module, announcementTypes {
|
||||
|
||||
mapping(address => bool) public genesis;
|
||||
|
||||
constructor(bool forReplace, address payable moduleHandler, address dbAddr, address payable icoContractAddr, address payable exchangeContractAddress, address payable[] memory genesisAddr, uint256[] memory genesisValue) public payable {
|
||||
constructor(bool forReplace, address payable moduleHandler, address dbAddr, address payable icoContractAddr, address payable exchangeContractAddress, address payable[] memory genesisAddr, uint256[] memory genesisValue) payable {
|
||||
/*
|
||||
Installation function
|
||||
|
||||
|
@ -18,7 +18,6 @@ contract CategoricalEvent is Event {
|
||||
Oracle _oracle,
|
||||
uint8 outcomeCount
|
||||
)
|
||||
public
|
||||
Event(_collateralToken, _oracle, outcomeCount)
|
||||
{
|
||||
|
||||
|
@ -34,7 +34,6 @@ abstract contract Event {
|
||||
/// @param _oracle Oracle contract used to resolve the event
|
||||
/// @param outcomeCount Number of event outcomes
|
||||
constructor(Token _collateralToken, Oracle _oracle, uint8 outcomeCount)
|
||||
public
|
||||
{
|
||||
// Validate input
|
||||
require(address(_collateralToken) != address(0) && address(_oracle) != address(0) && outcomeCount >= 2);
|
||||
|
@ -34,7 +34,6 @@ contract ScalarEvent is Event {
|
||||
int _lowerBound,
|
||||
int _upperBound
|
||||
)
|
||||
public
|
||||
Event(_collateralToken, _oracle, 2)
|
||||
{
|
||||
// Validate bounds
|
||||
|
@ -55,7 +55,7 @@ contract Campaign {
|
||||
}
|
||||
|
||||
modifier timedTransitions() {
|
||||
if (stage == Stages.AuctionStarted && deadline < now)
|
||||
if (stage == Stages.AuctionStarted && deadline < block.timestamp)
|
||||
stage = Stages.AuctionFailed;
|
||||
_;
|
||||
}
|
||||
@ -78,7 +78,6 @@ contract Campaign {
|
||||
uint _funding,
|
||||
uint _deadline
|
||||
)
|
||||
public
|
||||
{
|
||||
// Validate input
|
||||
require( address(_eventContract) != address(0)
|
||||
@ -86,7 +85,7 @@ contract Campaign {
|
||||
&& address(_marketMaker) != address(0)
|
||||
&& _fee < FEE_RANGE
|
||||
&& _funding > 0
|
||||
&& now < _deadline);
|
||||
&& block.timestamp < _deadline);
|
||||
eventContract = _eventContract;
|
||||
marketFactory = _marketFactory;
|
||||
marketMaker = _marketMaker;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user