This article will show you how to deploy FEVM-compatible smart contracts as deal clients on the Filecoin network. We will deploy the contract to Hyperspace, a developer-oriented test network. Hold on, you are wondering what is even this FEVM? We will start with some basics!
The Filecoin virtual machine (FVM) is a runtime environment for user-deployed smart contracts, known as actors, on the Filecoin network. You can find more details and its roadmap at https://fvm.filecoin.io. In March, developers can deploy EVM compatible smart contracts on FEVM, and later on any language that compiles to WASM on FVM.
Another question you might have is how does the Filecoin Virtual Machine come into play in today's Filecoin storage market?
The Filecoin Virtual Machine unlocks boundless possibilities, ranging from **programmable storage primitives** (such as storage bounties, auctions, and more) to data-centric Decentralized Autonomous Organizations (DAOs).
The Lotus team has been working on prototyping smart contracts that can enable storage marketplace primitives, codenamed PeSto. With this project, we want to enable developers to more easily understand the deal-making flow in the Filecoin network, and provide a solid deal client smart contract example that includes perpetual storage capabilities which can be deployed or further developed.
The project is still a WIP and there are currently a lot of intermediate steps! You can follow along the journey in this Github repo or the workshop at our Youtube channel! That being said, let´s take a look at how a bare minimum client contract works today by inspecting the deal client contract flow and the flow on the storage provider side.
<aside> 💙 If you prefer to follow along with demos, head to our Youtube channel playlist - Workshop: Data Client Contracts, Perpetual Storage and Data Daos on Filecoin!
</aside>
The Client contract is located in this repo, please go through the README before moving forward...
Now that you know what a client contract is, lets jump right into it by deploying the DealClient contract to the HyperSpace network before we go into the flow of the contract.
You can import the DealClient.sol contract to Remix with this Github-link:
<https://github.com/lotus-web3/client-contract/blob/main/src/DealClient.sol>
Importing DealClient.sol contract into Remix
Importing DealClient.sol contract into Remix
We need to comment out the first import line in DealClient.sol
to be able to compile the contract:
Comment out the first import line in DealClient.sol
Comment out the first import line in DealClient.sol
Before we can deploy the contract to the Hyperspace network, we need to set up our Metamask wallet to interact with the Hyperspace network. Go to chainlist.wtf, search for the Filecoin Hyperspace, click Connect Wallet
, and add the Hyperspace testnet to Metamask.
Once you have your MetaMask set up you can request funds for your wallet address with the Hyperspace faucet. It might take a couple of minutes before testFIL lands in your wallet. Now we are ready to deploy the contract:
Deploying the client contract to the Hyperspace network
Deploying the client contract to the Hyperspace network
Once the message has been included in a block (it can take a couple of minutes) you should see a log of it in your Remix console.
Open the transaction information by clicking on the debug
button, copy the transaction hash and paste it into a Hyperspace chain explorer to inspect the contract. Your contract is now live on the Filecoin Hyperspace network ✅.
<aside> ⚠️ Let’s stop here for a moment and explain a couple of IPFS and Filecoin related terms and formats before we go on!
</aside>
The CAR format
So what is this CAR thing? CAR stands for Content Addressable aRchives, and it is a format for bundling InterPlanetary Linked Data, IPLD, blocks into a large bundle. On the Filecoin network the majority of data is stored as large IPLD blocks.
You can read more about the CAR format here.
Sectors A sector is the default unit of storage that storage providers submit to the Filecoin network. On the mainnet storage providers can decide if they want to commit 32 GiB or 64 GiB sector sizes when they first initialize their storage provider on-chain. On the Hyperspace test network 512MiB sectors are also supported. A sector can contain data from multiple deals and clients.
PieceCID also known as commP (piece commitment)
The piece content identifier (CID) also known as commP (piece commitment), is the merkle root of the CAR file. We need to store this data in the deal information because it tells us where to find the deal data in a sector, which can be composed of several deals.
<aside> 💡 There are many toolings that developers can use for data preparation that’s provides simpler user experience, you can find more details here. In this tutorial, we will use lotus for demo purpose.
</aside>
Great! Now that we understand those concepts, lets start by generating a .CAR
testfile using the car - The CLI tool. You can install the latests version with:
go install github.com/ipld/go-car/cmd/car@latest
With this tool we can create a CAR test file with the commands:
touch testfile.txt
car create --version=1 --file testcar testfile.txt
We now have a CAR-file which we can inspect and get information about:
car inspect testcar
Version: 1
Roots: bafybeiamsh53xue7b42l4oflgbdoypled5w5hvijegjhrrjll57f2uk74u
Root blocks present in data: Yes
Block count: 2
Min / average / max block length (bytes): 60 / 85 / 110
Min / average / max CID length (bytes): 36 / 36 / 36
Block count per codec:
raw: 1
dag-pb: 1
CID count per multihash:
sha2-256: 2
We can now compute the pieceCID/commP for the testfile using this lotus command:
lotus client commP testcar
CID: baga6ea4seaqnyo6tkwpdme66jelyvyeucbb3a2njnhag5zzyls33otg7ll6bsni
Piece size: 508 B
Piece size in bytes: 508
Before we continue it is also useful to know what the padded piece size of the commP, as we will need to input the padded size into the addCID in the contract. For this we can either use a tool like stream-commp, or manually round it to the next power of 2.
cat testcar | stream-commp
CommPCid: baga6ea4seaqnyo6tkwpdme66jelyvyeucbb3a2njnhag5zzyls33otg7ll6bsni
Payload: 304 bytes
Unpadded piece: 508 bytes
Padded piece: 512 bytes
CARv1 detected in stream:
Blocks: 2
Roots: 1
1: bafybeiamsh53xue7b42l4oflgbdoypled5w5hvijegjhrrjll57f2uk74u
Great, now we have the commP for this testfile. As we can see in our Remix Deployed Contracts
dashboard we will have to turn this value into raw bytes:
The addCID in the contract only takes in raw bytes because it does not have a concept of CID.
We can turn the commP into raw bytes using the lotus-shed
tool.
./lotus-shed cid cborSer baga6ea4seaqnyo6tkwpdme66jelyvyeucbb3a2njnhag5zzyls33otg7ll6bsni
0181e203922020dc3bd3559e3613de49178ae0941043b069a969c06ee7385cb7b74cdf5afc1935
Now we are finally ready to add this CID to our contract. Take the output from the ./lotus-shed cid cborSer baga…
output, append 0x00 in front of it and paste into cidraw. The size should be the padded size that we found in the step where we generated the CAR file and inspected it:
Great! We have now deployed the contract and added a CID to the contract. We can use the lotus evm stat
command to get more information about our contract:
lotus evm stat 0x287064f4E0e1f497edBB5141D19f556d6ede8B2e
ID address: t06001
Code cid: bafk2bzacea6etsvrqejjl7uej5dxlswja5gxzqyggsjjvg27timvtiedf7nsg
Actor Type: fil/11/evm
Filecoin address: t410ffbygj5ha4h2jp3n3kfa5dh2vnvxn5czocemvdpa
Eth address: 0x287064f4e0e1f497edbb5141d19f556d6ede8b2e
Storage providers have a new command for interacting asynchronously with a client contract: lotus-miner storage-deals async-contract-deal
NAME:
lotus-miner storage-deals async-contract-deal - Async deal with client contract
USAGE:
lotus-miner storage-deals async-contract-deal [command options] <commP> <commPSize> <clientAddr> <startEpoch> <duration> <carFile>
OPTIONS:
--help, -h show help (default: false)
The command takes in a number arguments commP
,commPSize
, clientAddr
, startEpoch
, duration
and carFile
. When the storage provider executes the command it will start the asynchronous deal making process with the client contract. For the contract example and data in this guide the values would be:
commP - baga6ea4seaqnyo6tkwpdme66jelyvyeucbb3a2njnhag5zzyls33otg7ll6bsni
commPSize (unpadded) - 508
clientAddr (ID address of the contract) - t06001
startEpoch (block height) - 47200 - this must be set higher then the current block height, and should also take into account the sealing time as the sector must be sealed before the startEpoch.
duration (in epochs) - 576000
This process includes verification where the contract will authenticate making a deal for the given CID, it will create and publish a PublishStorageDeal (PSD) message which will show the deal details on-chain and it will create or add the data to a sector and seal it. Yes it’s just as easy as your other deal onboarding flow, see the whole flow in the video below if you wanna know more(starting 4’15’’)!
https://www.youtube.com/watch?v=uUpMZaTUC48&list=PLhmonklIHGmXu_uJ9JBvB6bA7hGb7tsXT&index=2
If you wanna try it out, join Hyperspace testnet and run your miner with this branch.
You might have noticed that this article skipped an essential step - How does the the storage provider get the data in the first place?
Going forward we will look at multiple possibilities, but one idea that we are currently exploring is enriching the client contract with more deal information and emitting events on actions like addCID
. This would allow an consumer of these event (either an SP or a third party) to subscribe the events and trigger deal creation accordingly.
We are also going to show how you can make client contracts as a verified client so that it can enjoy the cheap storage provided by Filecoin storage providers.
<aside> 💙 We would love to hear questions and feedbacks from you!
</aside>
Slack: #fil-lotus-announcements #fil-lotus-dev at filecoin.io/slack
GitHub: https://github.com/orgs/lotus-web3/
Twitter: https://twitter.com/lotus_web3 ****(follow us!)
Youtube: @lotus_web3 (Subscribe!)