Smart Contract Quick start
Developing smart contracts for Syscoin involves a bevy of off-chain tools used for producing and testing bytecode
that runs on the Network-Enhanced Virtual Machine (NEVM).
Some tools also include workflows for deploying this bytecode to the Syscoin network and testnets.
There are many options for these tools. This guide walks you through writing and testing a simple smart contract that
interacts with the Pegasys Protocol using one specific set of tools (truffle
+ npm
+ mocha
).
#
RequirementsTo follow this guide, you must have the following installed:
#
Bootstrapping a projectYou can start from scratch, but it's easier to use a tool like truffle
to bootstrap an empty project.
Create an empty directory and run npx truffle init
inside that directory to unbox the default
Truffle box.
#
Setting up npmIn order to reference the Pegasys contracts, you should use the npm artifacts we deploy containing the core and
periphery smart contracts and interfaces. To add npm dependencies, we first initialize the npm package.
We can run npm init
in the same directory to create a package.json
file. You can accept all the defaults and
change it later.
#
Adding dependenciesNow that we have an npm package, we can add our dependencies. Let's add the
@pollum-io/pegasys-protocol
package.
If you check the node_modules/@pollum-io/pegasys-protocol
directory, you can now find the Pegasys contracts.
#
Writing our contractWe can now get started writing our example contract. For writing Solidity, we recommend IntelliJ or VSCode with a solidity plugin, but you can use any text editor. Let's write a contract that returns the value of some amount of liquidity shares for a given token pair. First create a couple of files:
This will be the interface of the contract we implement. Put it in contracts/interfaces/ILiquidityValueCalculator.sol
.
Now let's start with the constructor. You need to know where the PegasysFactory
is deployed in order to compute the
address of the pair and look up the total supply of liquidity shares, plus the amounts for the reserves.
We can store this as an address passed to the constructor.
The factory address is constant on syscoin mainnet, so it may be tempting to make this value a constant in your contract, but since we need to unit test the contract it should be an argument. You can use solidity immutables to save on gas when accessing this variable.
Now we need to be able to look up the total supply of liquidity for a pair, and its token balances. Let's put this in a separate function. To implement it, we must:
- Look up the pair address
- Get the reserves of the pair
- Get the total supply of the pair liquidity
- Sort the reserves in the order of tokenA, tokenB
The PegasysLibrary
has some helpful methods for this.
Finally we just need to compute the share value. We will leave that as an exercise to the reader.
#
Writing testsIn order to test your contract, you need to:
- Bring up a testnet
- Deploy the
PegasysFactory
- Deploy at least 2 ERC20 tokens for a pair
- Create a pair for the factory
- Deploy your
LiquidityValueCalculator
contract - Call
LiquidityValueCalculator#computeLiquidityShareValue
- Verify the result with an assertion
#1 is handled for you automatically by the truffle test
command.
Note you should only deploy the precompiled Pegasys contracts in the build
directories for unit tests.
This is because solidity appends a metadata hash to compiled contract artifacts which includes the hash of the contract
source code path, and compilations on other machines will not result in the exact same bytecode.
This is problematic because in Pegasys we use the hash of the bytecode in the periphery
PegasysLibrary
,
to compute the pair address.
To get the bytecode for deploying PegasysFactory, you can import the file via:
We recommend using a standard ERC20 from @openzeppelin/contracts
for deploying an ERC20.
You can read more about deploying contracts and writing tests using Truffle here.
#
Compiling and deploying the contractLearn more about compiling and deploying contracts using Truffle here and here respectively.
#
WIPThis guide is a WIP. Please contribute to this guide with the edit button below!