mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
123 lines
4.8 KiB
ReStructuredText
123 lines
4.8 KiB
ReStructuredText
.. index:: ! contract;creation, constructor
|
|
|
|
******************
|
|
Creating Contracts
|
|
******************
|
|
|
|
Contracts can be created "from outside" via Ethereum transactions or from within Solidity contracts.
|
|
|
|
IDEs, such as `Remix <https://remix.ethereum.org/>`_, make the creation process seamless using UI elements.
|
|
|
|
One way to create contracts programmatically on Ethereum is via the JavaScript API `web3.js <https://github.com/ethereum/web3.js>`_.
|
|
It has a function called `web3.eth.Contract <https://web3js.readthedocs.io/en/1.0/web3-eth-contract.html#new-contract>`_
|
|
to facilitate contract creation.
|
|
|
|
When a contract is created, its :ref:`constructor <constructor>` (a function declared with
|
|
the ``constructor`` keyword) is executed once.
|
|
|
|
A constructor is optional. Only one constructor is allowed, which means
|
|
overloading is not supported.
|
|
|
|
After the constructor has executed, the final code of the contract is stored on the
|
|
blockchain. This code includes all public and external functions and all functions
|
|
that are reachable from there through function calls. The deployed code does not
|
|
include the constructor code or internal functions only called from the constructor.
|
|
|
|
.. index:: constructor;arguments
|
|
|
|
Internally, constructor arguments are passed :ref:`ABI encoded <ABI>` after the code of
|
|
the contract itself, but you do not have to care about this if you use ``web3.js``.
|
|
|
|
If a contract wants to create another contract, the source code
|
|
(and the binary) of the created contract has to be known to the creator.
|
|
This means that cyclic creation dependencies are impossible.
|
|
|
|
::
|
|
|
|
pragma solidity >=0.4.22 <0.7.0;
|
|
|
|
|
|
contract OwnedToken {
|
|
// `TokenCreator` is a contract type that is defined below.
|
|
// It is fine to reference it as long as it is not used
|
|
// to create a new contract.
|
|
TokenCreator creator;
|
|
address owner;
|
|
bytes32 name;
|
|
|
|
// This is the constructor which registers the
|
|
// creator and the assigned name.
|
|
constructor(bytes32 _name) public {
|
|
// State variables are accessed via their name
|
|
// and not via e.g. `this.owner`. Functions can
|
|
// be accessed directly or through `this.f`,
|
|
// but the latter provides an external view
|
|
// to the function. Especially in the constructor,
|
|
// you should not access functions externally,
|
|
// because the function does not exist yet.
|
|
// See the next section for details.
|
|
owner = msg.sender;
|
|
|
|
// We perform an explicit type conversion from `address`
|
|
// to `TokenCreator` and assume that the type of
|
|
// the calling contract is `TokenCreator`, there is
|
|
// no real way to verify that.
|
|
// This does not create a new contract.
|
|
creator = TokenCreator(msg.sender);
|
|
name = _name;
|
|
}
|
|
|
|
function changeName(bytes32 newName) public {
|
|
// Only the creator can alter the name.
|
|
// We compare the contract based on its
|
|
// address which can be retrieved by
|
|
// explicit conversion to address.
|
|
if (msg.sender == address(creator))
|
|
name = newName;
|
|
}
|
|
|
|
function transfer(address newOwner) public {
|
|
// Only the current owner can transfer the token.
|
|
if (msg.sender != owner) return;
|
|
|
|
// We ask the creator contract if the transfer
|
|
// should proceed by using a function of the
|
|
// `TokenCreator` contract defined below. If
|
|
// the call fails (e.g. due to out-of-gas),
|
|
// the execution also fails here.
|
|
if (creator.isTokenTransferOK(owner, newOwner))
|
|
owner = newOwner;
|
|
}
|
|
}
|
|
|
|
|
|
contract TokenCreator {
|
|
function createToken(bytes32 name)
|
|
public
|
|
returns (OwnedToken tokenAddress)
|
|
{
|
|
// Create a new `Token` contract and return its address.
|
|
// From the JavaScript side, the return type
|
|
// of this function is `address`, as this is
|
|
// the closest type available in the ABI.
|
|
return new OwnedToken(name);
|
|
}
|
|
|
|
function changeName(OwnedToken tokenAddress, bytes32 name) public {
|
|
// Again, the external type of `tokenAddress` is
|
|
// simply `address`.
|
|
tokenAddress.changeName(name);
|
|
}
|
|
|
|
// Perform checks to determine if transferring a token to the
|
|
// `OwnedToken` contract should proceed
|
|
function isTokenTransferOK(address currentOwner, address newOwner)
|
|
public
|
|
pure
|
|
returns (bool ok)
|
|
{
|
|
// Check an arbitrary condition to see if transfer should proceed
|
|
return keccak256(abi.encodePacked(currentOwner, newOwner))[0] == 0x7f;
|
|
}
|
|
}
|