Оглавление
- Function Types
- Visibility
- Во-вторых, видимость функции
- Take away
- ERC, ERC drafts and Smart contracts snippets / reference
- Overload resolution
- Overview of Functions
- Transactions and message calls
- State Variables
- Модификаторы видимости и ABI
- Как работают модификаторы?
- Operators Involving LValues
- Linting
- Formatting using Prettier and the Prettier Solidity Plugin
- Code generation Nethereum
- Hedera Hashgraph
- Part 4: Solidity Mappings
- Ethereum
- Use Structs as ValueTypes in mappings.
- Модификаторы на практике
- Storage
- Introduction to Parameters
Function Types
Solidity function types represent types of functions. Function type variables can be assigned from functions. To designate functions to and return functions from function calls, use function parameters.
The usage of function members is illustrated in this code example:
Example Copy
Members that the public and external functions can have:
- : retrieves the ABI function selector.
- : retrieves a callable function object. After that function is called, it sends the indicated amount of gas to the target function.
- : retrieves a callable function object. After that function is called, it sends the specified amount of wei to the target function.
The following example shows the usage of internal function. It can be applied to internal library functions because they will belong to the same code context:
Example Copy
This example shows the usage of external functions:
Example Copy
Call internal functions only on the current contract since they cannot be completed outside the context of the current contract.
External functions contain signatures of functions and addresses: such functions can be passed and returned from external function calls.
Notation of function types:
Example Copy
Function types are internal by default. Therefore, it is possible to remove the internal keyword. Remember that this is only applicable for function types.
Visibility
В solidity существует 4 типа ‘видимости’ функций и переменных — external, public, internal и private, стандартом является public. Для глобальных переменных стандартом является internal, а external невозможен. Итак, рассмотрим все варианты:
Для наглядности рассмотрим небольшой пример.
Одним из самых частых вопросов является ‘зачем нужны external функции, если всегда можно использовать public’. На самом деле, не существует случая, когда external нельзя заменить на public, однако, как я уже писал, в некоторых случаях это более эффективно. Давайте рассмотрим на конкретном примере.
Выполнение public функции стоит 413 газа, в то время как вызов external версии только 281. Происходит это потому, что в public функции происходит копирование массива в memory, тогда как в external функции чтение идет напрямую из calldata. Выделение памяти, очевидно, дороже, чем чтение из calldata.
Причина того, что public функциям нужно копировать все аргументы в memory в том, что они могут быть вызваны еще и изнутри контракта, что представляет из себя абсолютно другой процесс — как я уже писал ранее, они работают посредством прыжков в коде, а массивы передаются через указатели на memory. Таким образом, когда компилятор генерирует код для internal функции, он ожидает увидеть аргументы в memory.
Для external функций, компилятору не нужно предоставлять внутренний доступ, поэтому он предоставляет доступ к чтению данных прямо из calldata, минуя шаг копирования в память.
Таким образом грамотный выбор типа ‘видимости’ служит не только для ограничения доступа к функциям, но и позволяет использовать их эффективнее.
P.S.: В следующих статьях я перейду к разбору работы и оптимизации сложных типов на уровне байт-кода, а также напишу об основных уязвимостях и багах, присутствующих в solidity на данный момент.
Во-вторых, видимость функции
Solidity обеспечивает четыре типа видимости функций,,,,。
- Заявлено какМожно получить из других контрактов или черезСделайте звонок, чтобы объявление былоФункция является частью внешнего интерфейса контракта.
- Не может бытьСпособ звонка.
- Иногда производительность лучше при получении больших массивов данных.
Заявлено какизМожет быть толькоЧтобы позвонитьВызов отчета。
- По умолчанию функция объявлена как。
- Функция позволяет какТакже разрешено называтьСпособ звонка.
- Функция доступна по внешнему контракту и является частью внешнего интерфейса контракта.
Мы видим, что это утверждениеизРазрешены два метода вызова.
В текущем или унаследованном контракте толькоinternalСпособ звонка.
Приведенный выше пример объявлен какизВ определении договора и субподряда может быть толькоМетод можно вызвать.
- Доступ к нему можно получить только в текущем контракте (не в унаследованном контракте).
- Даже если заявлено как, Данные внутри могут быть просмотрены всеми. Права доступа только препятствуют доступу других контрактов к функциям или изменению данных.
В приведенном выше примере декларацияизМожет использоваться только в определенном контрактеСпособ звонка.
Об авторе
-
Подробнее читайте в разделе «Переданные данные функции» ссылки.http://me.tryblockchain.org/Solidity-call-callcode-delegatecall.html
Take away
In Solidity there are . The special variables and functions are always available globally and are mainly used to provide information about the blockchain (i.e., transactions, contract info, address info, error handling, math and crypto functions).
The global variables in particular are special global variables that contain properties which allow access to the blockchain’s contracts, their functions, and their values.
The global variable — likely the most commonly used special variable — is always the address where a current function call came from. For instance, if a function call came from a user or smart contract with the address then equals .
Lastly, the values of all members of , including and , can change for every external function call.
Interested is discussing global variables in Solidity further? Drop us a line! team@upstate.agency
ERC, ERC drafts and Smart contracts snippets / reference
It is pretty hard sometimes to find interfaces or information about an EIP (ERC) or specific libraries to simply get started working with Solidity.
The solidity extension now includes ERC approved and most drafts (wip) to help get you started.
Just type and select the erc example or interface you want.
Smart contract project interfaces
In a similar to way to ERCs and as we work towards to more interoperable smart contracts, being able to quickly examine those interfaces that you want to integrate is a time saver.
The current release includes the interfaces for Uniswap V2 (to get started), just type to list them all.
Note: If an ERC or your project is not included, please create a pull request. Note: Only established projets will be included.
Overload resolution
We have already explained it before. In our previous example, contains two functions but both have different parameters. These functions are called overload candidates.
When a call is made to function , the function selected is based on the arguments supplied to the function call. The arguments are compared to the function declarations and the right function is selected. This is called overload resolution.
As an example, let’s imagine I make the following call:
f(80, true)
Since we provide an and a as parameters, this will resolve automatically on :
function f(uint _in, bool _really) public
Overview of Functions
Internal, external, public and private Solidity functions modify variables and smart contracts.
Example Copy
- Internal functions are invoked inside the current contract and cannot be completed in different contexts.
- External functions are invoked from the outside and through transactions as well. It is not possible to call internally. When dealing with big arrays of information, these functions can be highly effective.
- Private functions are visible only inside the contract they are called in.
- The public functions are called from any place.
You can add these modifiers between the and parameters:
Example Copy
Modifiers
To change the way functions work, you can use Solidity modifiers. By using them, you can set a condition to check before the function execution.
In the example below, the contract does not use the modifier, only defines it. The derived contracts will use the modifier. The function body is inserted in the place the special symbol is in the modifier definition. When the owner calls this function, it executes. Otherwise, it throws an exception.
Example Copy
The following contract inherits the modifier from and uses it on function. After that, calls to will be effective if they are initiated by the stored owner:
Example Copy
Arguments can be set for modifiers:
Example Copy
Remember to set keyword to make sure that functions do not reject Ether:
Example Copy
Getter Methods
Solidity generates a getter function for every defined public state variable. Such a function has external visibility. In the example below, the compiler creates a function without any arguments. It returns the value of the state variable :
Example Copy
view
Functions set to do not change the state. These actions indicate a modification of the state:
- Creating other contracts
- Making Solidity transfer Ether through calls
- Writing to state variables
- Removing events
Example Copy
pure
Functions set to should not modify or read from the state. It prevents functions from:
- Calling functions that are not marked.
- Using inline assembly, containing specific opcodes.
- Reading from state variables.
- Accessing or .
- Accessing members of , , (except and ).
Example Copy
Fallback
Solidity fallback function does not have any arguments, has external visibility and does not return anything.
The function in the example below is invoked for all messages sent to this contract. Sending Ether to this contract triggers an exception since the fallback function is not set as :
Example Copy
The does not allow to retrieve Ether from it:
Example Copy
Solidity fallback function executes in such cases:
- If other functions do not equal the provided identifier, it works on a call to the contract.
- When a contract gets Ether without any other data, the function executes (if it is set as Solidity ).
- If there is enough gas, this function can execute like any other method.
Transactions and message calls
В Ethereum’е существует 2 вида аккаунтов, разделяющих одно и то же адресное пространство: External accounts — обычные аккаунты, контролируемые парами приватных-публичных ключей (или проще говоря аккаунты людей) и contract accounts — аккаунты, контролируемые кодом, хранящимся вместе с ними (смарт-контракты). Транзакция представляет из себя сообщение от одного аккаунта к другому (который может быть тем же самым, или же особым нулевым аккаунтом, смотрите ниже), содержащее какие-то данные (payload) и Ether.
С транзакциями между обычным аккаунтами все понятно — они всего-лишь передают значение. Когда целевым аккаунтом является нулевой аккаунт (с адресом 0), транзакция создает новый контракт, а его адрес формирует из адреса отправителя и его количества отправленных транзакций (‘nonce’ аккаунта). Payload такой транзакции интерпретируется EVM как байткод и выполняется, а вывод сохраняется как код контракта.
Если же целевым аккаунтом является contract account, выполняется код, находящийся в нем, а payload передается как входные данные. Самостоятельно отправлять тразакции contract account’ы не могут, однако можно запускать их в ответ на полученные (как от external account’ов, так и от других contract account’ов). Таким образом можно обеспечить взаимодействие контрактов друг с другом посредством внутренних транзакций (message calls). Внутренние транзакции идентичны обычным — они также имеют отправителя, получателя, Ether, gas и тд., а контракт может установить для них gas-limit при отправке. Единственное отличие от транзакций, созданных обычными аккаунтами, заключается в том, то живут они исключительно в среде исполнения Ethereum.
State Variables
You declare state variables in the part. State variables are stored in . The Solidity keyword indicates one of the possible storing locations.
Example Copy
Constant State Variables
It is possible to declare state variables with Solidity . This assignment takes place during the compiling process since it must be set from a constant expression.
Solidity does not permit expressions that reach storage, execution or blockchain data, or makes calls to external contracts.
Example Copy
State Variables in Storage: Layout
Solidity places variables that are statically-sized in storage from position 0 (except mapping and dynamically-sized array). It puts items that require less than 32 bytes into a single storage slot (if achievable).
Модификаторы видимости и ABI
С модификаторами видимости был легкий бардак, во многом обусловленный наличием значений по умолчанию. Накопилось достаточно много мелких правок, которые должны сделать язык более строгим, убрав эту путаницу.
А поскольку эти модификаторы попадают в ABI контракта, изменения коснулись и его.
- Все функции в интерфейсах надо явно помечать как external.
К сожалению, переопределить потом такую функцию как public в некоторых версиях компилятора нельзя — возникнет ошибка (например, в 0.4.21). Это стало возможным начиная с версии 0.4.22.
Также обещают разрешить реализовывать функции с помощью переменных. - Модификаторы видимости стали обязательными для функций.
Это изменение долго ждало своего часа. Issue на гитхабе создали сразу после первого хака Parity.
Дополнительное ограничение — fallback может быть только external.
Как работают модификаторы?
Давайте начнем с базовых примеров, приведенных ниже.
Символ _;
Символ _; называется подстановочным знаком. Он объединяет код функции с кодом модификатора.
Другими словами, тело функции (к которой присоединен модификатор) будет вставлено туда, где в определении модификатора появляется специальный символ _;.
Используя термины документации Solidity, этот символ «возвращает поток выполнения к исходному коду функции».
Модификатор должен содержать символ _; в своем теле. Это обязательно.
Куда поместить _; ?
Вместо _; будет подставлена функция, поэтому выполнение функции зависит от того места, где вы укажите этот символ: до, посредине или после основного кода модификатора.
Как показано в примере выше, вы можете поместить символ _; в начало, середину или конец тела модификатора.
На практике наиболее безопасной схемой использования является размещение _; в конце. В этом сценарии модификатор служит для последовательной проверки условий, то есть для того, чтобы сначала проверить условие, а затем продолжить выполнение функции. Приведенный ниже код демонстрирует это на примере:
Operators Involving LValues
The is an LValue (for instance, a variable or something that can be assigned to). It has operators as shorthands:
- is the same as . The operators , , , , , and are defined accordingly.
- and is the same as / but the expression still has the previous a value.
- and work the same on a but return the value after the change.
delete
In the following example, assigns to 0 and does not affect data. sets data to 0, does not affect :
Example Copy
- The sets the initial value for the type to . I.e. for integers it is equivalent to .
- It is possible to apply it on arrays. It will set a dynamic array of length zero or static array of the same length with all elements assigned their initial value.
- will remove an element at the specified array index (won’t change other items and length). This results in a gap in an array.
- It sets a struct with all members reset. The a value after is the same as delete does not influence mappings. By deleting a struct, you reset all members that are not related to mappings.
Linting
There are two linters included with the extension, solhint and solium / ethlint. You can chose your preferred linter using this setting, or disable it by typing »
Solhint
To lint Solidity code you can use the Solhint linter https://github.com/protofire/solhint, the linter can be configured it using the following user settings:
"solidity.linter": "solhint", "solidity.solhintRules": { "avoid-sha3": "warn" }
This extension supports configuration file. It must be placed to project root
directory. After any changes in it will be synchronized with current IDE
configuration.
This is the default linter now.
NOTE: Solhint plugins are not supported yet.
Solium / Ethlint
Solium is also supported by the extension https://github.com/duaraghav8/Solium, you can configure it using the following user settings:
"solidity.linter": "solium", "solidity.soliumRules": { "quotes": , "indentation": },
Formatting using Prettier and the Prettier Solidity Plugin
Formatting uses the default formatting settings provided by prettier, if you want to provide your custom settings create a .prettierrc file as follows
{ "overrides": }
If you would like to format on save, add this entry to your user / workspace settings:
Code generation Nethereum
The extension integrates with the Nethereum code generator to create Contract integration definitions. You can either generate the api for a single contract, all compiled contracts, or automatically every time you compile a smart contract solidity file.
The simplest way to code generate a the contract definition for a smart contract is to right click and select the project / language you require:
Hedera Hashgraph
Особенность Hedera Hashgraph в том, что сеть построена полностью с нуля и не использует технологии существующих блокчейн сетей, входящих в глобальную экосистему DeFi. Примечательно, что разработчики используют язык Solidity: это говорит о широком функционале этого языка программирования для разработки продвинутых блокчейн-сетей.
Вместо сложного и трудоемкого майнинга платформа Hedera Hashgraph предлагает иной алгоритм – ориентированный ациклический граф (Directed Acyclic Graph или DAG). Hedera Hashgraph – не блокчейн в привычном смысле этого слова. Сеть Hedera Hashgraph скорее можно представить в виде дерева графов.
Такая структура примечательна тем, что скорость транзакций увеличивается по мере добавления новых транзакций в сеть. Другими словами, транзакции в сети Hedera Hashgraph обрабатываются и подтверждаются параллельно, а не последовательно, как в сетях Bitcoin или Ethereum. Разработчики стремятся достичь пропускной способности, превышающей 100 000 транзакций в секунду, с минимальными затратами на вычисления.
Команда Hedera Hashgraph используют тот же язык, что и создатели Ethereum, для разработки смарт-контракта. Умные контракты в сети Hedera Hashgraph нужны, чтобы пользователи могли создавать собственные DApp-приложения поверх сети, используемые для разных целей: игры, DeFi-платформы, цифровая идентификация и многое другое.
Но у Hedera Hashgraph есть один существенный недостаток: в отличие от большинства проектов, платформа содержит закрытый исходный код, что осложняет аудит и не позволяет раскрыть замысел основателей. Кроме того, создатели Hedera Hashgraph запатентовали технологию, благодаря чему независимые разработчики не смогут создавать форки для улучшения работы протокола.
Заключение
Существует немного платформ, использующих язык Solidity для создания архитектуры и смарт-контрактов. Однако за время своего существования этот язык программирования стал стандартом для блокчейн-индустрии. Ведь многие ведущие платформы, такие как Ethereum, Binance Smart Chain, Polkadot и другие, созданы именно на Solidity. Однако, большинство разработчиков этих платформ не стремятся идти своим путем, а пытаются сместить Ethereum, заняв его почетное место в экосистеме DeFi.
Вместо того, чтобы просто конкурировать с Ethereum, разработчики Zhcash создали уникальную концепцию, использующую самые эффективные свойства блокчейнов. Zhcash использует гибридную модель для функционирования блокчейна, что позволяет валидаторам и стандартным узлам легко и быстро переключаться между алгоритмами консенсуса для наиболее эффективного взаимодействия.
Part 4: Solidity Mappings
Now let’s talk about another data structure called «Mappings», which let you store key-value pairs. Let me illustrate how this works:
This table above shows a key-value pair relationship. There are unique set of «keys» that correspond to unique values. Any information in the table can be looked up by its key. For example, if we ask for the value of «k1», then it will return «AAA,BBB,CCC». Likewise, new information can be stored under a new key. For example, we can add the value «ABCDEFG» to a new key called «k6».
This is exactly how mappings work inside Solidity, and they let you implement data-base like behavior in your smart contracts. For example, you can create mappings where they keys are
id
Let’s see how to create a mapping inside our smart contract like this:
We declare it with the keyword, and we specify the data type for the key and the value. In this case, each key in the mapping will be a , and each corresponding value will be a .
We’ll treat this mapping like a database of names, where each key is an id (, , …), and each value is a name («Adam», «Bryan», «Carl»…).
Now let’s see see how this mapping works in action. Fortunately, we already have a way to read information from this mapping since it has been declared . Solidity will provide us with a function called where we can pass in a key, and it will return the value.
In order to read data from the mapping, we must first add some names to it. We’ll do that in the constructor function like this:
Note, that we simply pass in the key within the brackets, and then assign the new value after the sign.
Yay, now try compiling and running your smart contract in Remix to observe this behavior. Simply call the function, and pass in an id (1, 2, or 3). For example, . If you get stuck, you can watch me do this in the video above.
Now let’s see how mappings can be used model more complex database-like behavior with smart contracts. Let’s create a database of books with mappings.
First, we’ll create a new struct to store specific data about a book like this:
Note, this book struct tracks the title and the author of the book.
Next, we’ll create a mapping where we can store books based upon a unique id like this:
See, here we can specify that key is a id, and the value is a .
Now we’ll create a function to add a new book like this:
This function accepts 3 arguments: id of the new book, title, and author. Inside the function, we build a new struct from these arguments, and add it too the mapping with th new id.
At this point, our complete books code should look like this:
Great! Now you can test this behavior out in the Remix interface after you compile the contract and run it. You can follow along with me in the video to see how.
Now let’s take this a step further and create a more complex database of books. Currently, all the books are stored in a database without a concept of individual ownership, i.e., a book has an «author», but not an «owner». We an create a way for individual users to own books by assigning ownership to an individual Ethereum address.
To do this, we’ll use a nested mappin like this:
This mapping is a nested mapping, which means that it’s a mapping INSIDE another mapping. In this case, the mapping uses an Ethereum address as the key, to represent the owner of the books, and this returns a new mapping as its value: a mapping ids to books (much like the mapping from the previous example).
We an add new books to this mapping like this:
Here we assign the new book to the mapping, using the sender’s address as the key (
Great! Now try to compile this code and test it in the Remix interface. At this point, your final smart contract should look like this:
Ethereum
Язык Solidity разработала команда Ethereum, которая на нем же и создала блокчейн-платформу. Сейчас сеть Ethereum является ведущей в мире среди проектов, работающих на смарт-контрактах. Ethereum создан в 2014, а его создателем стал Виталик Бутерин – одна из самых влиятельных персон в криптоиндустрии.
Ethereum предоставляет экосистему для разработки автономных децентрализованных приложений (DApps) и на ее основе были созданы крупнейшие DeFi-протоколы, такие как Uniswap, MakerDAO, Compound, Aave и многие другие. На самом деле, для Ethereum это не является преимуществом, поскольку чем больше приложений использует Ethereum, тем сильнее будет загружена сеть.
Стремительный рост популярности DeFi наглядно это продемонстрировал: из-за высокой пользовательской активности стоимость транзакций достигла небывалых высот, а иногда комиссии превышали $100 за транзакцию.
Платформу поддерживает огромное комьюнити, которое сформировалось за 7 лет существования Ethereum. Несмотря на такую популярность, сеть Эфира обладает проблемами с масштабируемостью, что приводит к медленным и дорогостоящим транзакциям.
Пока разработчики пытаются решить проблему, работая над обновлением Ethereum 2.0. Обновленная платформа будет полностью функционировать на алгоритме консенсуса Proof-of-Stake (PoS), а в основе протокола будет заложен дефляционный механизм, появившийся в сети после хардфорка London. Это значит, что часть монет, оплаченных за Gas, будут безвозвратно сжигаться, а эмиссия ETH – уменьшаться, соответственно.
Use Structs as ValueTypes in mappings.
The declaration below is a mapping that reference each Instructor by their ethereum address.
mapping(address => Instructor) instructors;
You can use this mapping to lookup a specific instructor with their ethereum address and retrieve their informations. The function below implements this functionality by returning a tuple that contains the instructor’s age, first name and last name.
pragma solidity ^0.5.0;contract Course { struct Instructor { uint age; string first_name; string last_name; } mapping(address => Instructor) instructors; function getInstructorInfos(address _instructor_address) public view returns (uint, string memory, string memory) { uint _age = instructors.age; string memory _first_name = instructors.first_name; string memory _last_name = instructors.last_name; return (_age, _first_name, _last_name); }}
You could also write the the , and directly in the statement for brevity, as shown below.
function getInstructorInfos(address _instructor_address) public view returns (uint, string memory, string memory) { return ( instructors.age, instructors.first_name, instructors.last_name );}
Going back to our previous example, you can’t return the mapping and iterate through all the instructors (because a mapping contains all the possible values by default).
Instead, you would need the following protocol:
- save all the ‘s addresses who registered in your contract in an array.
address[] public instructorAccounts;
2. Iterate through all the addresses stored he array
for (uint i = 0; i <= instructorAccounts.length; i++) { // logic goes here}
Модификаторы на практике
Только владелец или определенные пользователи
Можно использовать модификатор для проверки того, что функция может быть вызвана и выполнена только по определенному адресу.
Поддержка нескольких администраторов
Или вместо того чтобы ограничивать вызов функции только одним определенным пользователем, мы можем дать это право запуска функции нескольким заранее определенным пользователям.
Проверка данных
Еще один отличный вариант использования модификаторов — проверка вводимых данных.
Ниже приведены некоторые примеры, основанные на различных типах данных.
Возврат случайно отправленного eth
Мир блокчейна не допускает ошибок. Если eth или другие ценности были случайно отправлены не по адресу, то тут нет кого-то, к которому можно обратиться с претензиями, поскольку нет банка или центрального органа, контролирующего транзакции.
Однако вы можете подготовить свой смарт-контракт к непредвиденным ситуациям, сказав ему, что делать, когда пользователи ведут себя странно и шлют в ваши функции eth.
Взимать сборы
Ваш смарт-контракт может взимать сборы с пользователей, которые хотят вызвать определенную функцию вашего смарт-контакта.
Вернуть сдачу
Мы уже видели, как модификатор может быть использован для возврата eth, отправленных случайно на смарт-контракт. Но как насчет случая, когда пользователь отправляет больше eth, чем следовало бы?
Пример реализации выглядит следующим образом.
Переключение между состояниями
Модификатор может быть использован для сложных образцов проектирования. К ним относится образец проектирования — Машина состояний.
Запретить смарт-контрактам взаимодействовать со смарт-контрактами
SUSHISWAP приводит отличный пример модификатора, который позволяет только внешним учетным записям (т.е. пользователям) требовать вознаграждения по своему смарт-контракту.
В результате это не позволяет другим смарт-контрактам вызывать функцию, к которой прикреплен модификатор.
Проверка типа account’а
Этот модификатор дополняет предыдущий, который проверял, принадлежит ли address человеку или является смарт-контрактом. А этот модификатор проверяет есть ли по адресу код кода, используя опкод extcodesize(…) через assembly. Если есть, то это смарт-контракт.
Storage
If storage is specified, this will only stores a reference (It will not copy the struct). Assignments to the members of the local variable will write and modify the state. Here is a simple example.
contract Course {struct Professor { uint age; string name; } string constant course_name = "Painting";Professor public module_leader; constructor() public { module_leader.age = 138; module_leader.name = "Pablo Picasso"; }function modifyModuleLeader(uint _age, string memory _name) public { Professor storage new_module_leader = module_leader; new_module_leader.age = _age; new_module_leader.name = _name; }}
Introduction to Parameters
Currently, Solidity default parameters do not exist. This section reviews function parameters, return variables and event parameters.
Function Parameters
Just like in JavaScript, functions accept parameters as input. As output, Solidity functions can deliver an arbitrary number of values.
To make Solidity accept one type of external call with two integers, use this code:
Example Copy
Return Variables
Solidity defines the return variables by following the same syntax after the keyword . This example shows that two results will be returned (the sum and the product of two integers included as function parameters:
Example Copy
You can omit names of return variables. Use return variables as regular local variables. They have their default value (if not specified otherwise).
It is possible to explicitly assign to return variables and then leave the function using . Also, use statement to specify return values (single or multiple):
Example Copy
Event Parameters
A common question is how many parameters Solidity event can have. Event declaration is the same as function declaration. The usage of non-indexed parameters is less strict: the limit for such event arguments is 17.