Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/hyperledger/solang into dec…
Browse files Browse the repository at this point in the history
…larations

Signed-off-by: Govardhan G D <[email protected]>
  • Loading branch information
chioni16 committed Sep 22, 2023
2 parents 47bab7d + c53d8d9 commit 430a078
Show file tree
Hide file tree
Showing 116 changed files with 2,573 additions and 1,103 deletions.
3 changes: 3 additions & 0 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,11 @@ def setup(sphinx):
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx_tabs.tabs'
]

# Do not allow tabs to be closed
sphinx_tabs_disable_tab_closing = True
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down
2 changes: 2 additions & 0 deletions docs/examples/base_contract_function_call.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ abstract contract a {

function bar2() internal returns (uint64) {
// this explicitly says "call foo of base contract a", and dispatch is not virtual
// however, if the call is written as a.foo{program_id: id_var}(), this represents
// an external call to contract 'a' on Solana.
return a.foo();
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions docs/examples/solana/bobcat.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
anchor_anchor constant bobcat = anchor_anchor(address'z7FbDfQDfucxJz5o8jrGLgvSbdoeSqX5VrxBb5TVjHq');
interface anchor_anchor {
@program_id("z7FbDfQDfucxJz5o8jrGLgvSbdoeSqX5VrxBb5TVjHq")
interface bobcat {
@selector([0xaf, 0xaf, 0x6d, 0x1f, 0x0d, 0x98, 0x9b, 0xed])
function pounce() view external returns(int64);
}
5 changes: 2 additions & 3 deletions docs/examples/solana/contract_address.sol
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
@program_id("5kQ3iJ43gHNDjqmSAtE1vDu18CiSAfNbRe4v5uoobh3U")
contract hatchling {
string name;

Expand All @@ -9,7 +8,7 @@ contract hatchling {
}

contract adult {
function test(address addr) external {
hatchling h = new hatchling("luna");
function test(address id) external {
hatchling.new{program_id: id}("luna");
}
}
21 changes: 21 additions & 0 deletions docs/examples/solana/contract_call.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
contract Polymath {
function call_math() external returns (uint) {
return Math.sum(1, 2);
}
function call_english(address english_id) external returns (string) {
return English.concatenate{program_id: english_id}("Hello", "world");
}
}

@program_id("5afzkvPkrshqu4onwBCsJccb1swrt4JdAjnpzK8N4BzZ")
contract Math {
function sum(uint a, uint b) external returns (uint) {
return a + b;
}
}

contract English {
function concatenate(string a, string b) external returns (string) {
return a + b;
}
}
21 changes: 21 additions & 0 deletions docs/examples/solana/contract_new.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@program_id("5afzkvPkrshqu4onwBCsJccb1swrt4JdAjnpzK8N4BzZ")
contract hatchling {
string name;
address private origin;

constructor(string id, address parent) {
require(id != "", "name must be provided");
name = id;
origin = parent;
}

function root() public returns (address) {
return origin;
}
}

contract adult {
function test() external {
hatchling.new("luna", address(this));
}
}
7 changes: 2 additions & 5 deletions docs/examples/solana/create_contract_with_metas.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import 'solana';

contract creator {
Child public c;
Child public c_metas;

function create_with_metas(address data_account_to_initialize, address payer) public {
AccountMeta[3] metas = [
AccountMeta({
Expand All @@ -20,9 +17,9 @@ contract creator {
is_signer: false})
];

c_metas = new Child{accounts: metas}(payer);
Child.new{accounts: metas}(payer);

c_metas.use_metas();
Child.use_metas();
}
}

Expand Down
6 changes: 6 additions & 0 deletions docs/examples/solana/expression_this.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
contract kadowari {
function nomi() public {
// Contracts are not allowed as variables on Solana
address a = address(this);
}
}
10 changes: 10 additions & 0 deletions docs/examples/solana/expression_this_external_call.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
@program_id("H3AthiA2C1pcMahg17nEwqr9628gkXUnnzWJJ3iSDekL")
contract kadowari {
function nomi() public {
this.nokogiri(102);
}

function nokogiri(int256 a) public {
// ...
}
}
27 changes: 27 additions & 0 deletions docs/examples/solana/function_call.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
contract A {
function test(address v) public {
// the following four lines are equivalent to "uint32 res = v.foo(3,5);"

// Note that the signature is only hashed and not parsed. So, ensure that the
// arguments are of the correct type.
bytes data = abi.encodeWithSignature(
"global:foo",
uint32(3),
uint32(5)
);

(bool success, bytes rawresult) = v.call(data);

assert(success == true);

uint32 res = abi.decode(rawresult, (uint32));

assert(res == 8);
}
}

contract B {
function foo(uint32 a, uint32 b) pure public returns (uint32) {
return a + b;
}
}
16 changes: 16 additions & 0 deletions docs/examples/solana/function_call_external.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
contract foo {
function bar1(uint32 x, bool y) public returns (address, bytes32) {
return (address(3), hex"01020304");
}

function bar2(uint32 x, bool y) public returns (bool) {
return !y;
}
}

contract bar {
function test(address f) public {
(address f1, bytes32 f2) = foo.bar1{program_id: f}(102, false);
bool f3 = foo.bar2{program_id: f}({x: 255, y: true});
}
}
24 changes: 24 additions & 0 deletions docs/examples/solana/function_type_callback.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
contract ft {
function test(address p) public {
// this.callback can be used as an external function type value
paffling.set_callback{program_id: p}(this.callback);
}

function callback(int32 count, string foo) public {
// ...
}
}

contract paffling {
// the first visibility "external" is for the function type, the second "internal" is
// for the callback variables
function(int32, string) external internal callback;

function set_callback(function(int32, string) external c) public {
callback = c;
}

function piffle() public {
callback(1, "paffled");
}
}
5 changes: 2 additions & 3 deletions docs/examples/solana/payer_annotation.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ import 'solana';

@program_id("SoLDxXQ9GMoa15i4NavZc61XGkas2aom4aNiWT6KUER")
contract Builder {
BeingBuilt other;
function build_this() external {
// When calling a constructor from an external function, the data account for the contract
// 'BeingBuilt' should be passed as the 'BeingBuilt_dataAccount' in the client code.
other = new BeingBuilt("my_seed");
BeingBuilt.new("my_seed");
}

function build_that(address data_account, address payer_account) public {
Expand All @@ -30,7 +29,7 @@ contract Builder {
is_signer: false
})
];
other = new BeingBuilt{accounts: metas}("my_seed");
BeingBuilt.new{accounts: metas}("my_seed");
}
}

Expand Down
17 changes: 13 additions & 4 deletions docs/examples/solana/program_id.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,23 @@ contract Foo {
}
}

contract Bar {
Foo public foo;
contract OtherFoo {
function say_bye() public pure {
print("Bye from other foo");
}
}

contract Bar {
function create_foo() external {
foo = new Foo();
Foo.new();
}

function call_foo() public {
foo.say_hello();
Foo.say_hello();
}

function foo_at_another_address(address other_foo_id) external {
OtherFoo.new{program_id: other_foo_id}();
OtherFoo.say_bye{program_id: other_foo_id}();
}
}
51 changes: 42 additions & 9 deletions docs/language/contracts.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,24 @@ Instantiation using new
_______________________

Contracts can be created using the ``new`` keyword. The contract that is being created might have
constructor arguments, which need to be provided.
constructor arguments, which need to be provided. While on Polkadot and Ethereum constructors return the address
of the instantiated contract, on Solana, the address is either passed to the call using the ``{program_id: ...}`` call
argument or is declared above a contract with the ``@program_id`` annotation. As the constructor does not return
anything and its purpose is only to initialize the data account, the syntax ``new Contract()``is not idiomatic on Solana.
Instead, a function ``new`` is made available to call the constructor.

.. tabs::

.. group-tab:: Polkadot

.. include:: ../examples/polkadot/contract_new.sol
:code: solidity

.. include:: ../examples/polkadot/contract_new.sol
:code: solidity

.. group-tab:: Solana

.. include:: ../examples/solana/contract_new.sol
:code: solidity

The constructor might fail for various reasons, for example ``require()`` might fail here. This can
be handled using the :ref:`try-catch` statement, else errors cause the transaction to fail.
Expand Down Expand Up @@ -87,15 +101,16 @@ can use. gas is a ``uint64``.
.. include:: ../examples/polkadot/contract_gas_limit.sol
:code: solidity


.. _solana_constructor:

Instantiating a contract on Solana
__________________________________
Solana constructors
___________________

On Solana, the contract being created must have the ``@program_id()`` annotation that specifies the program account to
which the contract code has been deployed. This account holds only the contract's executable binary.
When calling a constructor only once from an external function, no call arguments are needed. The data account
necessary to initialize the contract should be present in the IDL and is identified as ``contractName_dataAccount``.
Solidity contracts are coupled to a data account, which stores the contract's state variables on the blockchain.
This account must be initialized before calling other contract functions, if they require one. A contract constructor
initializes the data account and can be called with the ``new`` function. When invoking the constructor from another
contract, the data account to initialize appears in the IDL file and is identified as ``contractName_dataAccount``.
In the example below, the IDL for the instruction ``test`` requires the ``hatchling_dataAccount`` account to be
initialized as the new contract's data account.

Expand Down Expand Up @@ -125,6 +140,24 @@ The sequence of the accounts in the ``AccountMeta`` array matters and must follo
:ref:`IDL ordering <account_management>`.


.. _solana_contract_call:

Calling a contract on Solana
____________________________

A call to a contract on Solana follows a different syntax than that of Solidity on Ethereum or Polkadot. As contracts
cannot be a variable, calling a contract's function follows the syntax ``Contract.function()``. If the contract
definition contains the ``@program_id`` annotation, the CPI will be directed to the address declared inside the
annotation.

If that annotation is not present, the program address must be manually specified with the ``{program_id: ... }`` call
argument. When both the annotation and the call argument are present, the compiler will forward the call to the address
specified in the call argument.

.. include:: ../examples/solana/contract_call.sol
:code: solidity


Base contracts, abstract contracts and interfaces
-------------------------------------------------

Expand Down
28 changes: 24 additions & 4 deletions docs/language/expressions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,15 +112,35 @@ ____
The keyword ``this`` evaluates to the current contract. The type of this is the type of the
current contract. It can be cast to ``address`` or ``address payable`` using a cast.

.. include:: ../examples/expression_this.sol
:code: solidity
.. tabs::

.. group-tab:: Polkadot

.. include:: ../examples/polkadot/expression_this.sol
:code: solidity


.. group-tab:: Solana

.. include:: ../examples/solana/expression_this.sol
:code: solidity

Function calls made via this are function calls through the external call mechanism; i.e. they
have to serialize and deserialise the arguments and have the external call overhead. In addition,
this only works with public functions.

.. include:: ../examples/expression_this_external_call.sol
:code: solidity
.. tabs::

.. group-tab:: Polkadot

.. include:: ../examples/polkadot/expression_this_external_call.sol
:code: solidity


.. group-tab:: Solana

.. include:: ../examples/solana/expression_this_external_call.sol
:code: solidity

.. note::

Expand Down
Loading

0 comments on commit 430a078

Please sign in to comment.