solana.rst 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. Solana
  2. ======
  3. The Solana target requires `Solana <https://www.solana.com/>`_ v1.8.1.
  4. Solana has the following differences to Ethereum Solidity:
  5. - The address type is 32 bytes, not 20 bytes. This is what Solana calls an "account"
  6. - An address literal has to be specified using the ``address"36VtvSbE6jVGGQytYWSaDPG7uZphaxEjpJHUUpuUbq4D"`` syntax
  7. - There is no ``ecrecover()`` builtin function, but there is a ``signatureVerify()`` function which can check ed25519
  8. signatures.
  9. - There is no concept of gas, so there is no gas functions
  10. - Solana balance is stored in a ``uint64``, so *address* ``.balance``, ``.transfer()`` and ``.send()``
  11. all use ``uint64`` rather than ``uint256``.
  12. - Solana uses different accounts for the program code, and the contract data.
  13. - Programs are upgradable. There is no need to implement upgrades in Solidity.
  14. - Solana provides different builtins, e.g. ``tx.program_id`` and ``tx.accounts``.
  15. - Function selectors are eight bytes and known as *discriminators*.
  16. This is how to build your Solidity for Solana:
  17. .. code-block:: bash
  18. solang compile --target solana flipper.sol -v
  19. This will produce two files called `flipper.json` and `flipper.so`. The former is an Anchor style IDL file and the latter is
  20. the ELF BPF shared object containing the program. For each contract in the source code, Solang will create both an IDL file
  21. and a binary file.
  22. Each program will need to be deployed to a program_id. Usually, the program_id is a well-known account which is specified
  23. in the Solidity source code using the `@program_id("F1ipperKF9EfD821ZbbYjS319LXYiBmjhzkkf5a26rC")` annotation on the contract.
  24. A private key for the account is needed to deploy. You can generate your own private key using the command line tool
  25. ``solana-keygen``.
  26. .. code-block:: bash
  27. echo "[4,10,246,143,43,1,234,17,159,249,41,16,230,9,198,162,107,221,233,124,34,15,16,57,205,53,237,217,149,17,229,195,3,150,242,90,91,222,117,26,196,224,214,105,82,62,237,137,92,67,213,23,14,206,230,155,43,36,85,254,247,11,226,145]" > flipper-keypair.json
  28. solana program deploy flipper.so
  29. After deploying the program, you can start on the client side, which needs the anchor npm library:
  30. .. code-block:: bash
  31. npm install @project-serum/anchor
  32. Write the following javascript to a file called `flipper.js`.
  33. .. code-block:: javascript
  34. const { readFileSync } = require('fs');
  35. const anchor = require('@project-serum/anchor');
  36. const IDL = JSON.parse(readFileSync('./flipper.json', 'utf8'));
  37. const PROGRAM_SO = readFileSync('./flipper.so');
  38. (async function () {
  39. const provider = anchor.AnchorProvider.env();
  40. const dataAccount = anchor.web3.Keypair.generate();
  41. const programId = new anchor.web3.PublicKey(IDL.metadata.address);
  42. const wallet = provider.wallet.publicKey;
  43. const program = new anchor.Program(IDL, programId, provider);
  44. await program.methods.new(wallet, true)
  45. .accounts({ dataAccount: dataAccount.publicKey })
  46. .signers([dataAccount]).rpc();
  47. const val1 = await program.methods.get()
  48. .accounts({ dataAccount: dataAccount.publicKey })
  49. .view();
  50. console.log(`state: ${val1}`);
  51. await program.methods.flip()
  52. .accounts({ dataAccount: dataAccount.publicKey })
  53. .rpc();
  54. const val2 = await program.methods.get()
  55. .accounts({ dataAccount: dataAccount.publicKey })
  56. .view();
  57. console.log(`state: ${val2}`);
  58. })();
  59. Now you'll have to set the `ANCHOR_WALLET` and `ANCHOR_PROVIDER_URL` environment variables to the correct values in order to run the example.
  60. .. code-block:: bash
  61. export ANCHOR_WALLET=$HOME/.config/solana/id.json
  62. export ANCHOR_PROVIDER_URL=http://127.0.0.1:8899
  63. node flipper.js
  64. For more examples, see the
  65. `solang's integration tests <https://github.com/hyperledger/solang/tree/main/integration/solana>`_.
  66. Using the Anchor client library
  67. _______________________________
  68. Some notes on using the anchor javascript npm library.
  69. * Solidity function names are converted to camelCase. This means that if in Solidity a function is called ``foo_bar()``,
  70. you must write ``fooBar()`` in your javascript.
  71. * Anchor only allows you to call ``.view()`` on Solidity functions which are declared ``view`` or ``pure``.
  72. * Named return values in Solidity are also converted to camelCase. Unnamed returned are given the name ``return0``, ``return1``, etc,
  73. depending on the position in the returns values.
  74. * Only return values from ``view`` and ``pure`` functions can be decoded. Return values from other functions and are not accessible.
  75. This is a limitation in the Anchor library. Possibly this can be fixed.
  76. * In the case of an error, no return data is decoded. This means that the reason provided in ``revert('reason');`` is not
  77. available as a return value.
  78. * Number arguments for functions are expressed as ``BN`` values and not plain javascript ``Number`` or ``BigInt``.
  79. .. _call_anchor:
  80. Calling Anchor Programs from Solidity
  81. _____________________________________
  82. It is possible to call `Anchor Programs <https://github.com/coral-xyz/anchor>`_
  83. from Solidity. You first have to generate a Solidity interface file from the IDL file using
  84. the :ref:`idl_command`. Then, import the Solidity file in your Solidity using the
  85. ``import "...";`` syntax. Say you have an anchor program called `bobcat` with a
  86. function `pounce`, you can call it like so:
  87. .. include:: ../examples/solana/call_anchor.sol
  88. :code: solidity
  89. Setting the program_id for a contract
  90. _____________________________________
  91. When developing contracts for Solana, programs are usually deployed to a well
  92. known account. The account can be specified in the source code using an annotation
  93. ``@program_id``. If you want to instantiate a contract using the
  94. ``new ContractName()`` syntax, then the contract must have a program_id annotation.
  95. .. include:: ../examples/solana/program_id.sol
  96. :code: solidity
  97. .. note::
  98. The program_id `Foo5mMfYo5RhRcWa4NZ2bwFn4Kdhe8rNK5jchxsKrivA` was generated using
  99. the command line:
  100. .. code-block:: bash
  101. solana-keygen grind --starts-with Foo:1
  102. Setting the payer, seeds, bump, and space for a contract
  103. _________________________________________________________
  104. When a contract is instantiated, there are two accounts required: the program account to hold
  105. the executable code and the data account to save the state variables of the contract. The
  106. program account is deployed once and can be reused for updating the contract. When each
  107. Solidity contract is instantiated (also known as deployed), the data account has to be
  108. created. This can be done by the client-side code, and then the created blank account
  109. is passed to the transaction that runs the constructor code.
  110. Alternatively, the data account can be created by the constructor, on chain. When
  111. this method is used, some parameters must be specified for the account
  112. using annotations. Those are placed before the constructor. If there is no
  113. constructor present, then an empty constructor can be added. The constructor
  114. arguments can be used in the annotations.
  115. .. include:: ../examples/solana/constructor_annotations.sol
  116. :code: solidity
  117. Creating an account needs a payer, so at a minimum the ``@payer`` annotation must be
  118. specified. If it is missing, then the data account must be created client-side.
  119. The ``@payer`` requires an address. This can be a constructor argument or
  120. an address literal.
  121. The size of the data account can be specified with ``@space``. This is a
  122. ``uint64`` expression which can either be a constant or use one of the constructor
  123. arguments. The ``@space`` should at least be the size given when you run ``solang -v``:
  124. .. code-block:: bash
  125. $ solang compile --target solana -v examples/flipper.sol
  126. ...
  127. info: contract flipper uses at least 17 bytes account data
  128. ...
  129. If the data account is going to be a
  130. `program derived address <https://docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses>`_,
  131. then the seeds and bump have to be provided. There can be multiple seeds, and an optional
  132. single bump. If the bump is not provided, then the seeds must not create an
  133. account that falls on the curve. The ``@seed`` can be a string literal,
  134. or a hex string with the format ``hex"4142"``, or a constructor argument of type
  135. ``bytes``. The ``@bump`` must a single byte of type ``bytes1``.
  136. .. _value_transfer:
  137. Transferring native value with a function call
  138. ______________________________________________
  139. The Solidity language on Ethereum allows value transfers with an external call
  140. or constructor, using the ``auction.bid{value: 501}()`` syntax.
  141. Solana Cross Program Invocation (CPI) does not support this. This means that:
  142. - Specifying ``value:`` on an external call or constructor is not permitted
  143. - The ``payable`` keyword has no effect
  144. - ``msg.value`` is not supported
  145. .. note::
  146. A naive way to implement this is to let the caller transfer
  147. native balance and then inform the callee about the amount transferred by
  148. specifying this in the instruction data. However, it would be trivial to
  149. forge such an operation.
  150. Receive function
  151. ________________
  152. In Solidity the ``receive()`` function, when defined, is called whenever the native
  153. balance for an account gets credited, for example through a contract calling
  154. ``account.transfer(value);``. On Solana, there is no method that implements
  155. this. The balance of an account can be credited without any code being executed.
  156. ``receive()`` functions are not permitted on the Solana target.
  157. .. _msg_sender_solana:
  158. ``msg.sender`` not available on Solana
  159. ______________________________________
  160. On Ethereum, ``msg.sender`` is used to identify either the account that submitted
  161. the transaction, or the caller when one contract calls another. On Ethereum, each
  162. contract execution can only use a single account, which provides the code and data.
  163. On Solana, each contract execution uses many accounts. Consider a rust contract which
  164. calls a Solidity contract: the rust contract can access a few data accounts, and which
  165. of those would be considered the caller? So in many cases there is not a single account
  166. which can be identified as a caller. In addition to that, the Solana VM has no
  167. mechanism for fetching the caller accounts. This means there is no way to implement
  168. ``msg.sender``.
  169. The way to implement this on Solana is to have an authority account for the contract
  170. that must be a signer for the transaction (note that on Solana there
  171. can be many signers too). This is a common construct on Solana contracts.
  172. .. include:: ../examples/solana/use_authority.sol
  173. :code: solidity
  174. Builtin Imports
  175. ________________
  176. Some builtin functionality is only available after importing. The following structs
  177. can be imported via the special builtin import file ``solana``.
  178. .. code-block:: solidity
  179. import {AccountMeta, AccountInfo} from 'solana';
  180. Note that ``{AccountMeta, AccountInfo}`` can be omitted, renamed or imported via
  181. import object.
  182. .. code-block:: solidity
  183. // Now AccountMeta will be known as AM
  184. import {AccountMeta as AM} from 'solana';
  185. // Now AccountMeta will be available as solana.AccountMeta
  186. import 'solana' as solana;
  187. .. note::
  188. The import file ``solana`` is only available when compiling for the Solana
  189. target.
  190. .. _account_info:
  191. Builtin AccountInfo
  192. +++++++++++++++++++
  193. The account info of all the accounts passed into the transaction. ``AccountInfo`` is a builtin
  194. structure with the following fields:
  195. address ``key``
  196. The address (or public key) of the account
  197. uint64 ``lamports``
  198. The lamports of the accounts. This field can be modified, however the lamports need to be
  199. balanced for all accounts by the end of the transaction.
  200. bytes ``data```
  201. The account data. This field can be modified, but use with caution.
  202. address ``owner``
  203. The program that owns this account
  204. uint64 ``rent_epoch``
  205. The next epoch when rent is due.
  206. bool ``is_signer``
  207. Did this account sign the transaction
  208. bool ``is_writable``
  209. Is this account writable in this transaction
  210. bool ``executable``
  211. Is this account a program
  212. .. _account_meta:
  213. Builtin AccountMeta
  214. +++++++++++++++++++
  215. When doing an external call (aka CPI), ``AccountMeta`` specifies which accounts
  216. should be passed to the callee.
  217. address ``pubkey``
  218. The address (or public key) of the account
  219. bool ``is_writable``
  220. Can the callee write to this account
  221. bool ``is_signer``
  222. Can the callee assume this account signed the transaction
  223. Builtin create_program_address
  224. ++++++++++++++++++++++++++++++
  225. This function returns the program derived address for a program address and
  226. the provided seeds. See the Solana documentation on
  227. `program derived addresses <https://edge.docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses>`_.
  228. .. include:: ../examples/solana/builtin_create_program_address.sol
  229. :code: solidity
  230. Builtin try_find_program_address
  231. ++++++++++++++++++++++++++++++++
  232. This function returns the program derived address for a program address and
  233. the provided seeds, along with a seed bump. See the Solana documentation on
  234. `program derived addresses <https://edge.docs.solana.com/developing/programming-model/calling-between-programs#program-derived-addresses>`_.
  235. .. include:: ../examples/solana/builtin_try_find_program_address.sol
  236. :code: solidity
  237. Solana Library
  238. ______________
  239. In Solang's Github repository, there is a directory called ``solana-library``. It contains libraries for Solidity contracts
  240. to interact with Solana specific instructions. We provide two libraries: one for SPL tokens and another
  241. for Solana's system instructions. In order to use those functionalities, copy the correspondent library
  242. file to your project and import it.
  243. SPL-token
  244. +++++++++
  245. `spl-token <https://spl.solana.com/token>`_ is the Solana native way of creating tokens, minting, burning and
  246. transferring token. This is the Solana equivalent of
  247. `ERC-20 <https://ethereum.org/en/developers/docs/standards/tokens/erc-20/>`_ and
  248. `ERC-721 <https://ethereum.org/en/developers/docs/standards/tokens/erc-721/>`_. Solang's repository contains
  249. a library ``SplToken`` to use spl-token from Solidity. The file
  250. `spl_token.sol <https://github.com/hyperledger/solang/blob/main/solana-library/spl_token.sol>`_ should be copied into
  251. your source tree, and then imported in your solidity files where it is required. The ``SplToken`` library has doc
  252. comments explaining how it should be used.
  253. There is an example in our integration tests of how this should be used. See
  254. `token.sol <https://github.com/hyperledger/solang/blob/main/integration/solana/token.sol>`_ and
  255. `token.spec.ts <https://github.com/hyperledger/solang/blob/main/integration/solana/token.spec.ts>`_.
  256. System Instructions
  257. +++++++++++++++++++
  258. Solana's system instructions enable developers to interact with Solana's System Program. There are functions to
  259. create new accounts, allocate account data, assign accounts to owning programs, transfer lamports from System Program
  260. owned accounts and pay transaction fees. More information about the functions offered can be found both on
  261. `Solana documentation <https://docs.rs/solana-program/1.11.10/solana_program/system_instruction/enum.SystemInstruction.html>`_
  262. and on Solang's `system_instruction.sol <https://github.com/hyperledger/solang/blob/main/solana-library/system_instruction.sol>`_ file.
  263. The usage of system instructions needs the correct setting of writable and signer accounts when interacting with Solidity
  264. contracts on chain. Examples are available on Solang's integration tests.
  265. See `system_instruction_example.sol <https://github.com/hyperledger/solang/blob/main/integration/solana/system_instruction_example.sol>`_
  266. and `system_instruction.spec.ts <https://github.com/hyperledger/solang/blob/main/integration/solana/system_instruction.spec.ts>`_