|
|
|
@ -173,6 +173,101 @@ defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do |
|
|
|
|
|
|
|
|
|
assert {:error, :compilation} = response |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
test "returns constructor in abi" do |
|
|
|
|
code = """ |
|
|
|
|
pragma solidity ^0.4.22; |
|
|
|
|
|
|
|
|
|
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. This also applies |
|
|
|
|
// to functions and especially in the constructors, |
|
|
|
|
// you can only call them like that ("internally"), |
|
|
|
|
// because the contract itself does not exist yet. |
|
|
|
|
owner = msg.sender; |
|
|
|
|
// We do 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 check that. |
|
|
|
|
creator = TokenCreator(msg.sender); |
|
|
|
|
name = _name; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function changeName(bytes32 newName) public { |
|
|
|
|
// Only the creator can alter the name -- |
|
|
|
|
// the comparison is possible since contracts |
|
|
|
|
// are implicitly convertible to addresses. |
|
|
|
|
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 also want to ask the creator if the transfer |
|
|
|
|
// is fine. Note that this calls a function of the |
|
|
|
|
// contract defined below. If the call fails (e.g. |
|
|
|
|
// due to out-of-gas), the execution here stops |
|
|
|
|
// immediately. |
|
|
|
|
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 is simply |
|
|
|
|
// `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); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function isTokenTransferOK(address currentOwner, address newOwner) |
|
|
|
|
public |
|
|
|
|
view |
|
|
|
|
returns (bool ok) |
|
|
|
|
{ |
|
|
|
|
// Check some arbitrary condition. |
|
|
|
|
address tokenAddress = msg.sender; |
|
|
|
|
return (keccak256(newOwner) & 0xff) == (bytes20(tokenAddress) & 0xff); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
""" |
|
|
|
|
|
|
|
|
|
name = "OwnedToken" |
|
|
|
|
compiler_version = "v0.4.22+commit.4cb486ee" |
|
|
|
|
|
|
|
|
|
{:ok, %{"abi" => abi}} = |
|
|
|
|
CodeCompiler.run( |
|
|
|
|
name: name, |
|
|
|
|
compiler_version: compiler_version, |
|
|
|
|
code: code, |
|
|
|
|
evm_version: "byzantium", |
|
|
|
|
optimize: true |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
assert Enum.any?(abi, fn el -> el["type"] == "constructor" end) |
|
|
|
|
end |
|
|
|
|
end |
|
|
|
|
|
|
|
|
|
describe "get_contract_info/1" do |
|
|
|
|