# Smart Contracts For interaction with Ethereum from C# code, we use [Nethereum](https://github.com/Nethereum/Nethereum). For interaction with Ethereum smart contracts, **Nethereum** has the *Contract* class. We get the contract via the **Web3** object associated with a RPC url and (optionally) an Account. ```csharp= Web3 web3 = new Web3(new Account("private-key"), "https://localhost:8584"); Contract myToken = web3.GetContract("abi", "contract-address"); ``` This class has the *GetFunction* method which returns the *Function* object. After retrieving the function, we can call *CallAsync* to sign and send the transaction. (NOTE: this method works only if the underlying Web3 object knows how to sign, i.e. provided `Account` in the constructor) ```csharp= Function transfer myToken.GetFunction("transfer"); await transfer.CallAsync<BigInteger>("from", "to", 1000000000); ``` For more information, see the [official documentation](https://nethereum.readthedocs.io). ## Wrapping SC in C# Flashboys tries to utilize OOP as much as possible as it has proven to be a best practice while consuming and extending your projects with new smart contract functionalities. Every contract extends the *BaseContract* class: ```csharp= public abstract class ContractService { public ContractService(Web3 web3, string abi, string contractAddress) { Abi = abi; Contract = web3.Eth.GetContract(abi, contractAddress); Web3 = web3; } public Web3 Web3 { get; } public string Abi { get; } public string ContractAddress => Contract.Address; public Contract Contract { get; } } ``` Now, for example, if we need to wrap a standard ERC20 contract, we have something like this: ```csharp= public class ERC20ContractService : ContractService { public ERC20ContractService(Web3 web3, string abi, string address) : base(web3, abi, address) { BalanceOf = Contract.GetFunction("balanceOf"); Transfer = Contract.GetFunction("transfer"); TransferFrom = Contract.GetFunction("transferFrom"); Approve = Contract.GetFunction("approve"); Decimals = Contract.GetFunction("decimals"); } public Function BalanceOf { get; set; } public Function Transfer { get; set; } public Function TransferFrom { get; set; } public Function Approve { get; set; } public Function Decimals { get; set; } public async Task<T> GetBalanceOfAsync<T>(string address) => await BalanceOf.CallAsync<T>(address); public async Task<T> GetDecimals<T>() => await Decimals.CallAsync<T>(); } ``` We see that *view* functions have default implementations (methods that call the node), but transactions (functions that change the state of the blockchain) are not wrapped. The reason for this is that some use-cases may have different approaches for calling these methods (for example, if we want to burst out 20 TXs we need a mechanism of nonce incrementing or if we have a custom signer method). If that's not the case and you just want to make an ordinary call from one address, you can use the `CallAsync()` on exposed public properties. ## SC to RESTful API Exposing smart contract functions over REST APIs is simple straightforward: - after the base url (`api` prefix, versions, etc.) goes the token address, for example: `baseUrl/api/v1.0/0xB591BE04E84fDE870FD4C1997D35E84F41a1bBdb/...`; if the contract represents a token or follows a naming convention (has the `name` or `symbol` method) then we can use it instead of the address, for example: `baseUrl/api/v1.0/IOTKN/...` - `view` functions are exposed with a `GET` endpoint; if the function takes some parameters, these parameters go inside URL query params, for example: `baseUrl/token/balanceOf?address=0xC92a1E04384fDE870FD4C1997D3cc74F41a1b621` - `transactions` (state changing functions) are exposed with a `POST` endpoint; the parameters of the function go in the body of the request, for example: ``` POST baseUrl/token721/transfer { "to": "0xC92a1E04384fDE870FD4C1997D3cc74F41a1b621", "tokenId": 153399863 } ``` ### Authorization In order to sign and send any transaction, we need to have the signing private key. We're looking at the case where the API manages the private keys of the consumers. Private keys are sensitive, meaning that losing them or not storing them safe can harm the owner of the address as he can lose all his funds or never gain access to them. For most use cases, Flashboys uses Azure KeyVault or HashiCorp Vault as they prove to be high-end secure HSM modules. These vaults are behave as simply key-value stores (dictionaries). After storing the private keys safely, we need to retrieve them when users call our endpoints. The mapping between some API specific `userId` and his private key varies from case to case: - API uses `Auth0` as an identification provider so we can use the `user_metadata` for storing the Ethereum address (which we use as a lookup key in the vaults) or we simply use the `auth0_user_id` as a Vault key - storing userId in a database together with the lookup - API key as a lookup ### Error handling It's known that besides classic Ethereum errors (wrong signature, known transaction, skipping nonces, out of gas, etc.) we can have manual developer-defined errors in our smart contracts - using `require`. The `require` instruction specifies a second argument - error message: ```javascript= function transfer(address to, uint256 amount) public { require(balance[to] >= amount, "Not enough balance"); } ``` Unfortunately, the message cannot be retrieved in consumer code (Nethereum, Web3js) at the moment of writing (Solidity 0.5.7, Parity 2.5.4, Geth 1.8.27). This leaves no other choice than to check every `require` statement on the API side manually. Let's have a quick look how we could implement `/token20/transfer`: ```csharp= public IHttpActionResult Transfer(TransferModel model) { // return the ethereum address from the vault based // on whatever parameter from the request string consumerAddress = GetCallerAddress(); if (Contract.BalanceOf(consumerAddress) < model.Amount) return BadRequest("Not enough balance."); if (model.To == AddressUtil.ZeroAddress) return BadRequest("Bad address specified"); // transfer wrapper string txHash = Contract.Transfer(GetCallerPrivateKey(), model.To, model.Amount); // log the transaction or save it to a database Logger.Log(MsgType.Information, $"Transfer tx {txHash}"); return Ok(); } ```