Solidity Contracts Examples
This set of smart-contract samples illustrates standard functionality of smart-contracts developed in Solidity, starting with very basic and gradually evolving into code snippets, which may come handy in production smart-contracts.
- You can find a list of all the contracts listed in this EverX (formerly TON Labs) repository.
1. Accumulator : persistent storage
Smart-contracts deployed to the blockchain store their state variables in a persistent storage.
Call Accumulator.add(uint value)
. It adds value
to its state variable sum
.
Resulting state of the account can be examined by conventional means.
2. StorageClient: calling another contract
Contracts can also call other remote contracts. Call StorageClient.store(Storage storageAddress)
to
invoke a public function of another contract. The remote contract UintStorage
saves the integer
value of the argument and the caller address in its state variables.
3. Borrower: EVER transfer
This sample demonstrates how currency transfer works. Call Borrower.askForALoan(Loaner loanerAddress, uint amount)
.
This requests amount
of currency from the contract deployed at the specified address.
The remote contract LoanerContract
transfers amount
of currency to the caller via msg.sender.transfer(amount)
.
Each contract has an internal transaction counter. The counter value increases with each transaction
and is stored in the persistent memory.
4. CurrencyExchange: callback implementation
Call CurrencyExchange.updateExchangeRate(address bankAddress, uint16 code)
. This function allows
interacting with a remote contract by calling its function: ICentralBank.GetExchangeRate(uint16 code)
.
The remote contract CentralBank
obtains caller's address via msg.sender
and performs a callback.
- Bank: loan interaction between Bank and BankClient
Call Bank.setAllowance(address bankClientAddress, uint amount)
.
Bank stores information about loan allowances and current debts for different contracts. This data
is recorded in the following state variable: mapping(address => CreditInfo) clientDB;
A contract owner is supposed to call the setAllowance()
function to specify limits.
BankClient is a client that can interact with Bank.
Call BankClient.getMyCredit(IBank bank)
.
This function calls the remote contract Bank to receive allowed credit limit via Bank invoking the
callback function setCreditLimit(uint limit)
.
Call BankClient.askForALoan(IBank bank, uint amount)
.
This function call the remote contract Bank to get an amount of credit. According to the current
credit info of the BankClient contract Bank will approve the credit via calling the callback
function "receiveLoan(uint n_totalDebt)" or refuse the credit via calling the callback function
refusalCallback(uint availableLimit)
.
receiveLoan function also obtains balance of the contract via address(this).balance and
balance of the inbound message via msg.value and saves them in state variables.
refusalCallback function saves the argument (available credit limit) in the state variable.
6. DataBase: exchange of different types of values
One of contract functions call allows sending to the DataBaseClient different values:
- uint64 array;
- five uint arrays;
- five uint256;
- struct array.
7. Giver: simple giver contract
This sample shows usage of different types of currency transactions and usage of a fallback function.
Call Giver.transferToAddress(address payable destination, uint amount)
or
Giver.do_tvm_transfer(address payable remote_addr, uint128 ton_value, bool bounce, uint16 sendrawmsg_flag)
to perform a currency transaction.
Call Giver.transferToCrashContract(address payable destination, uint amount)
to implement a crash
during transaction. That will cause an exception in CrashContract
and Giver's contract fallback function calling.
Call Giver.transferToAbstractContract(address payable destination, uint amount)
with a
non-existent address AbstractContract will also call a fallback function of Giver.
8. Kamikaze: selfdestruct function
Call Kamikaze.sendAllMoney(address anotherContract)
. This function destroys the contract and sends
all its funds to the specified address of Heir
contract.
9. PiggyBank: Piggy bank with two clients
This sample consists of 3 contracts:
- PiggyBank - piggy bank itself.
- PiggyBank_Owner - piggy bank's owner - valid user, who can add to piggy bank's deposit and withdraw.
- PiggyBank_Stranger - stranger - invalid user, who can add to piggy bank but can not withdraw.
Call PiggyBank_Owner.addToDeposit(PiggyBank bankAddress, uint amount)
or
PiggyBank_Stranger.addToDeposit(PiggyBank bankAddress, uint amount)
to transfer EVERs from the
contract to PiggyBank.
Call PiggyBank_Owner.withdrawDeposit(PiggyBank bankAddress)
of PiggyBank_Stranger.withdrawDeposit(PiggyBank bankAddress)
to try to withdraw the deposit from PiggyBank. Transfer would occur only for the owner.
10. Wallet: Simple wallet
Call Wallet.sendTransaction(address payable dest, uint128 value, bool bounce)
. This function
allows transferring EVERs to the specified account.
11. ContractDeployer: Deploy Contract from contract via new
.
The way to get arguments for deploying is described How to deploy contract from contract.
12. BadContract: Contract upgrade
Contract code could be changed via using tvm.setcode function. It could be useful for fixing errors and functionality updating. In that example we have a BadContract (it is a PiggyBank contract with added upgrade functionality) and new version of that contract NewVersion.
Call "PiggyBank.setCode(TvmCell memory newcode)" with argument that contains code of NewVersion contract to change the code of the contract.
13. BankCollector: Mapping methods
Developer can work with mappings using methods: fetch, min, next. This methods allow to check existence of the key, obtain lexicographically minimal key and lexicographically next key respectively.
14. CustomReplayProtection: Custom replay protection
Developer can redefine function afterSignatureCheck to create his own replay protection function instead of default one.
15. MessageSender: Message construction and parsing
Developer can use TVM specific types to build message manually and special api function tvm.sendrawmsg() to send it. Contract MessageSender performs such actions to build a message which will call the function of another contract MessageReceiver. MessageReceiver also shows how to parse a cell.
16. onBounceHandler: Working with bounced messages
Developer can define onBounce function to work with bounced messages. If an error occurs while message transferring or handling it can be bounced back to the source contract. This sample demonstrates how you can handle such bounced message.
17. low_level: Constructor message structure
18. Interfaces, OrderClient, OrderDatabase: Order Book
Interface.sol - interface of DataBase and Client Contract.
OrderClient.sol - contract that can create new orders in OrderDatabase contract.
OrderDtatabase.sol - stores order information, creates an order, changes the database, etc.
19. Casino, CasinoClient, CasinoOwner, CasinoInterfaces: Casino
Casino - Casino roulette smart contract.
CasinoInterfaces.sol - interface of the Casino contract.
CasinoOwner.sol, CasinoClient.sol - Casino owner smart contracts.
20. Bomber, Interface, Sink: Bomber
21. Self_deploy: Self Deployer
This sample shows how the contract can deploy another contract of the same type.
22. Sender, Sink: Sender
Generates cell which contains message which calls another contract by internal outbound message. Saves received value in state variable.
23. rawReserve, sender: Reserver
A contract that reserves a certain amount of EVER from the remaining balance of the account: exactly,at most,or all but.
24. ISquareProvider, LengthProvider, SquareProvider, WidthProvider: Rectangle square
25. Config: Function arguments specification
Sometimes it can be not obvious in which way function arguments should be specified, especially if it is a large structure with different and complex fields. It is generally described in abi doc. And this example was made to help users clear this moment.