The Auction Smart Contract¶
This chapter takes a further look at the smart contract-specific parts of an Auction C# class. You can check out the complete source here
public class Auction : SmartContract
The first line in the contract is a reference to the
Stratis.SmartContracts NuGet package. This package allows you to inherit from the
SmartContract class and thereby provides subclasses with useful functionality such as sending funds, hashing, and saving data. You can create smart contracts just by including the
Stratis.SmartContracts NuGet package in your project and inheriting from
The only libraries that can be included in the current iteration of Stratis smart contracts are
public Address Owner
The Auction object has several properties which are structured in a similar way to the Owner property. To persist data in a smart contract, use
PersistentState. Data can be persisted anywhere in the smart contract not just inside a property. However, persisting data inside properties makes the code inside your methods easier to read.
Address class is included as part of
Stratis.SmartContracts. It is an abstraction over a series of strings that enables funds to be sent to addresses.
public ulong GetBalance(Address address)
private void SetBalance(Address address, ulong balance)
The above methods emulate a dictionary-like structure for storage. Using a standard .NET dictionary would require serializing and deserializing all the dictionary data every time it was updated. For dictionaries with thousands of entries (think balances of a token contract), this would require a significant amount of processing. These methods instead store individual items in the underlying key/value store.
public Auction(ISmartContractState smartContractState, ulong durationBlocks)
Owner = Message.Sender;
EndBlock = Block.Number + durationBlocks;
HasEnded = false;
The contract constructor gets run when the contract is created for the first time. Contracts must override the base class constructor and inject
ISmartContractState, which must be the first parameter of the constructor. Other parameters should be positioned after this parameter.
Block objects are read-only properties on the
SmartContract class which the Auction class inherits from. These properties provide access to information about the current context that a contract call is executing in. For example: block numbers, the address that called the contract, etc.
Assigning a value to
HasEnded saves the values in
PersistentState via their property setters. Setting
Owner is a very common pattern when developing smart contracts and gives extra functionality to the creator of the contract. You will notice that in the
AuctionEnd method, funds are sent to
Assert method, inherited from
SmartContract, provides a simple way to reject contract executions that don’t meet certain criteria. In this case, we’re using it to reject any further execution when the message sender doesn’t have a balance in our contract.
Transfer method, also inherited from
SmartContract, enables the sending of funds to a specific address. This will send funds to ordinary addresses or contracts. A third parameter can be specified as input for this method to give more information about the method etc. to call on a contract.
public bool Withdraw()
ulong amount = GetBalance(this.Message.Sender);
Assert(amount > 0);
ITransferResult transferResult = Transfer(this.Message.Sender, amount);
There are a few more methods in the
Auction class, but the final method to look at is
Withdraw. This method checks whether the caller has a balance to withdraw from. If they do, this balance will be deducted from the smart contract state and they will be sent the funds.
You may be wondering why there is a
Withdraw method at all. Why not just transfer the funds to their owner as soon as they become available? The reason is because the owner of these funds could be another smart contract that cannot be controlled. Sending the funds back to such a contract would potentially call unknown code using another user’s funds. Therefore, the
Withdraw pattern is very common in smart contracts. If users call a contract, that contract execution should never execute an untrusted smart contract’s code.