Building Blockchain Apps Part 1: Tellor, Corda, Chainlink, Mintbase, Nervos | Unitize Day 3

Developer workshops from Unitize conference covering blockchain app building. Patrick Collins demonstrates Chainlink integration, while Tanner Allard teaches smart contracts in Rust on Nervos. Technical deep dives into decentralized application development.
Chapters
It's. Sam.
Hello everyone and welcome back to day three of Unitize. I hope you're excited as we have another full day of developer track sessions prepared for you. If you have any questions during any of the talks, please feel free to ask them in chat. Our speakers will answer them accordingly. I also want to inform everyone that that the virtual hackathon is currently ongoing. If you're a developer, please take a look at the exciting challenges we have going on. There are many prizes involved. Without further ado, let's get started. For our first talk, I'd like to welcome Patrick Collins, developer advocate at Chainlink, who will give a workshop on what can you do with chainlink right now. In this workshop, Patrick will help you explore the possibilities on Chainlink, the different tools you can use with Chainlink to build, and how you can connect your smart contracts to off chain data. Patrick, the stage is all yours.
Sa.
What's going on? Uniti's hackathon engineers and blockchain enthusiasts. At this exact point in time, we have an extraordinary opportunity in front of us. The world of smart contracts is knocking at our doorstep and history will show who will be the pioneers to push us into the fourth industrial revolution. But that's not going to happen unless we get to interact with the outside world and connect these smart contracts to off team data, APIs and traditional payments. So let's get right into it. Let's talk about Chainlink, the problem that it solves, how it solves it, where Chainlink is already now, some of the untapped potential that it has and the tools you can use now to become a part of history. So in order to understand Chainlink, we must first understand that smart contracts are not able to regularly connect to external data or or any off chain resource on their own. This is a big limiting factor for smart contract adoption because it means the only thing that we can currently do in a smart contract is token transfers. So you might be asking, why can't I just make a regular API call? That's what I do in every other language. And this is really important. And the simple answer is that the blockchain is deterministic and it needs to be validated by all blockchain nodes of the chain. If making API calls is part of the validation, then each node would get wildly different results in the case of an API being updated, depreciated or even hacked. So to interact with the outside world, we need to call what's called an Oracle, any device that interacts with the off chain world to provide data to smart contracts. They report the result of that data on chain so that the blockchain can see stay deterministic. This is a crucial, crucial piece of the blockchain and this is also where chainlink comes in. It's connecting with this off chain data and storing it on chain. There are thousands of APIs out there that are already providing high quality data that people need for their applications. We make it easy to enable connectivity between those APIs and smart contracts, even if they require authentication, so that you can have decentralized applications powered by the same reliable APIs that the rest of the world and current wealth applications use today. A single chainlink Oracle is called a chainlink node and I'll be using them a little bit interchangeably moving forward. Now a lot of users today still don't understand the blockchain and sending payments and cryptocurrencies isn't quite universally accepted yet. When a smart contract is executed, people need the ability to get paid in a currency that they want. Chainlink makes it easy for off chain payments to take place based on on chain interactions. This also works for cross chain communication and sending payments to other chains. Chainlink uses something called external adapters and we'll talk more about that later. To enable connectivity to any resource, be it an open API, an API that requires authentication, payments API or another blockchain. It works essentially as a wrapper around an API so that you can make these upgrades to provide authentication, processing or anything to reduce on chain gas costs and privacy. External adapters can be written in any language you want and they only need to react to specific requests sent to a chainlink node. Because of this, it's very easy to introduce new functionality to chainlink without needing to know anything about solidity or even Ethereum. Now here's where we turn up the heat a little bit. A centralized Oracle service or a centralized Oracle or a centralized node becomes a single point of flow failure for the entire smart contract. This is why we create decentralized oracles. Saying the chainlink node by itself is decentralized is kind of like calling a tree a forest. One single entity does not make up the whole to make applications that are truly never needed to rely on one entity, be it a company, a landlord or government or anything of the sort, you need a network of chainlink nodes. Why am I stressing this point? Well, we've already seen attacks that have lost projects literally millions of dollars since their centralized Oracle was hijacked. So chainlink is designed to be a modular infrastructure and can build a decentralized Oracle network used to connect smart contracts to any API. You can select as many Oracle nodes or chainlink nodes as we call them as you like and use as many data sources as you like in order to trigger the execution of your smart contracts. Then again, Chainlink also enables off chain payments based off of these decentralized Oracles for the execution of the smart contract. So if the result of a smart contract said that someone should get paid $100 USD, you can utilize Chainlink to send that transaction to get you started with DEFI or decentralized finance. The Chainlink project has gone ahead and found many of the best blockchain node operators on the planet and combine their prowess to build what's called reference data contracts or price reference contracts or reference contracts. These are decentralized on chain reference points that can be considered source of truth for various currency pairs like the price of eth in terms of USD for example. Each node in the network independently gets data from some of the Highest quality data APIs and reports their answers on chain. You can see the answers that each provider reports so that everything is transparent. Many of the most popular cryptocurrency or fiat currency pairs are currently supported and the best part is if you don't like it, you can always create your own network anyways. Currently these reference contracts are already being used by a slew of some of the top defi projects in the world. The proven safety, reliability and powerfulness of these applications is a testament to to the power and security that Chainlink has and to reference contracts. Here are some of the projects that are currently using Chainlink in the defi space. We have Synthetix, Loopring, Set, Protocol, AAVE and these all have acquired large amounts of secured dollars for their projects. Some other places that are starting to get some traction but aren't quite there yet is the gaming realm until now. And here's a big reason why getting random numbers on chain has been an issue since the current conventional way to get a random number you have to rely on the ethminers for a random hash or a Centralized API like random.org that can be hacked, hijacked or even changed. Chainlink has a decentralized provably random system and the surface is barely even scratched. We saw one project implement the Chainlink vrf, our last hackathon and one product push the gaming potential into the limelight with their no loss betting application. So this is one of the areas of blockchain that I want to emphasize because there is a huge opportunity here. The Defi Project Pool Together has also implemented the Chainlink vrf allowing their no loss audited savings game to be truly unpredictable, which is crucial for the project. They currently have about three quarters of a million dollars worth of DAI and they're constantly growing. This brings me to our next point. We have a blog that gives a list of ideas to power your smart contract. So if you're coming into this hackathon and you have no idea what to do, I definitely recommend you check that out. The blockchain space is literally thirsting for chain linked secured decentralized applications. Let me rapid fire some off. Let me rapid fire some of my favorite ideas off. So first off, Defi, as we mentioned before, is constantly one of the major areas of pushing for project and has a ton of momentum and knowledge from people working in the field. Chainlink supports already some of the top projects in Defi at the moment. There's over $1 billion in assets in decentralized finance, which is a huge accomplishment and major milestone. And you may think, wow, a billion dollars. That's a lot. But then you have to compare it a little bit. It's not even 0.1% of the traditional finance space. The math is too hard for me to calculate how small it is. The average hedge fund has over a billion dollars, and there are over 700 hedge funds that have singular hedge funds that have over a billion dollars and about $3.2 trillion in asset managed managers in general. And we're not even talking about how much money banks, high net worth individuals or other financial instruments are securing. Chandler makes integrating with financial instruments really easy with reference data contracts. Now this may seem like an insurmountable feat to reach these heights, to reach what the traditional finance world currently has, but I promise you, it's here, it's here and it's right now, and it's knocking at the door. The window of opportunity though, won't last forever. But we're here to make sure we can build some amazing tools and have fun doing it.
Boom.
Next one fantasy sports fantasy sports players pay on average $100 per league on a decentralized application on blockchain, you can cut that down by a fraction of a fraction without having to trust that the scores are being updated unfairly or the odds being skewed. Texas Hold' Em or any card board game. Chainlink VRFs make this possible with giving access to truly random numbers while still being way cheaper than a buy in at a major Texas hold' Em tournament. Tokenized assets. You can split up your car plots of land, shares of stock, making it easy to keep track of who owns what without having to deal with paperwork. And since your data is coming from decentralized oracles, nobody can mess it up. Insurance, this one really hits home for me. Let's say you're a farmer and your crops are all ruined from two seasons where the weather was terrible and your insurance, being a centralized entity, has decided that they're not going to pay out because some pre existing condition. Now you can go to court and you can fight it and you could win, which would be great. You would still have to go through all this time and effort to fighting the insurance company through court. Or worst case scenario, you go through all that pain and you still lose. With a decentralized smart contract, you don't have to trust that insurance company is going to do the right thing. Since the right thing is infrastructural with.
Chainlink.
By this time you should understand what the power that chainlink has when involved with smart contract. So let's dive right into what exactly this looks like at an engineering level. We're going to be going over the reference data contract first because it is the easiest implementation of chainlink while also being one of the most powerful. If you're using a DEFI technology like Uniswap Compound or any DEFI technology, a quick check on their Oracles with a chainlink price reference feed called a chainlink anchor can save you heartache, bug fixing, panics and possibly millions of dollars down the road. Let's see what that looks like now. So if you're looking to use reference data contracts or price reference data, first thing you want to do, just come right to the docs docs have all the information that you're looking for, talking about how it works, the aggregator interface and everything. Now something important to note is that the syntax for all these is for Truffle and for Node js. We'll get to that in a little bit. For now we're going to be using Remix, which is an Ethereum IDE which and it's really, really powerful for just spinning things up quickly on a test net and seeing exactly what it's going to look like when you actually deploy to mainnet and interacting with it really efficiently. So go over the truffle in a little bit. But basically what we're going to want to do is come here, you can read everything that you didn't know and we have a complete example at the bottom, which is great. We have this little, little copy paste button right here and you just copy it, come over to your Remix id, hit this little plus tab, make a new file and paste it into here. So I cut it down a little bit to make it simpler. And you know, all these functions that we have here are to interact with the reference contract easier. So we have get latest timestamp to see where we are. You can see the previous answers, you can go back as far as you want and get the previous timestamp as well. I cut it down to be just get the latest price and if that's all you want, this is literally how small your contract can be. So the other important thing when dealing with Remix, it doesn't work with that nice Node JS syntax that we saw. So we're actually importing directly from GitHub. Be sure to look at our boilerplates to make sure that you have the right link and we'll have a link to that as well. But yeah, we're going to start with solidity version 6. We're going to import from GitHub. We're going to start our contract, which again, if you're new to Solidity, this is kind of similar to starting a class. We have our aggregate interface, internal ref, which is kind of like a global variable. We have our constructor which is the same as any other language. It's. Once this gets deployed on a test net, this is what gets called and we have this get latest price, which literally calls, Literally calls from this reference feed and we can see a full list, a full list of reference data contracts for pretty much any pair that you can think of. Be sure to note that they start or that the addresses are different on mainnet and the different testnet. So EthUSD will have a different address for Ropson than it will for mainnet. Be sure to test on testnet before you go right into mainnet. And again, if you want to see what these feeds look like, you can come to the feeds chain link page and you can see, okay, well what are the nodes looking like? Who's returning what answer? And you come to here and you can literally see the visualization and all the data around here are the node operators that were returning data. And here's the aggregated the consensus of the answer in the middle here, which is really cool. So going back to Remix, super simple code, it's literally this small. We have it in here. Great. We're going to choose. Our version is going to be Solidity brings this file up here. We're going to choose our file, which is. Which I called referencedata Sol for solidity files you need to do. So we're going to compile. It's going to compile everything. Great. Looks like compiled successfully. Let's go ahead and deploy. We're going to want to go to Injected Web3 here. It's going to ask for our permission for MetaMask to connect. So if you're unsure how MetaMask works, be sure to follow our other tutorials in the docs and follow our videos as well that show you how to install MetaMask so you can work with this really, really easily. You can also learn how to get Test eth and Test link so that you don't have to pay any money when deploying these test contracts and playing around with them. So great. So we have brave giving me money. Yes. Great. So we're going to do inject the web3 which is literally taking a web provider, sticking it in our browser here. This deploy button right here is what's going to deploy the contract. And the address that we're looking for is going to be here. This is the address of that reference contract that we were talking about. And again, we can get that list for full list of reference contracts. We can get that from here again, which just has everything and you literally just copy and paste that into right here and it'll be whatever feed you want. So we've copied from ETH USD, not this one, we've copied from this one right here on the Ropsten because we're on the Ropsten testnet right now. Place it in here. We're going to deploy the contract. MetaMask is going to pop up, say are you sure about that? And we're going to say, yes, we're definitely sure about that. It's going to give us a link and it's the same as deploying pretty much any contract. You wait a couple minutes, you wait a couple seconds. Once it gets deployed, we're good to go. And you'll see it actually pop up in the bottom left of your remix screen. You can click that and it'll show all of our functions and how we can actually interact with this contract. Since we only have one function, this GetLatestPrice, and it's a view function, which means it's not actually changing any state. We're not actually going to be sending receiving any link. We're literally just reading from the blockchain. We don't have to pay anything. So we can just call it and MetaMask will not pop up and it will give us the Response of the price Reference contract, which is 2, $255.81 which is great. And as you can see, it looks like it's a lot more. That's because it's been multiplied. Because blockchain doesn't work with decimals very well. But that's it. It's that simple. Now you can take this and do some simple stuff like you know, if anchor is less than 10% of Oracle, this is some pseudocode here. Then don't run Smart Contract literally that simple. And the rest of the integrations are literally that easy too. So the next step I would say would to be do this request and receive data tutorial. We have a video coming out on it as well as the docs are really thorough. I highly recommend doing it in remix first so that you really go in depth and figuring out how it works. On testnet contract we have video on our chainlink YouTube. You guys should definitely check it out. That goes really in depth at it. But we're going to skip that one for now. We're going to go to setting up a chainlinked project using Truffle and using Node js. This is a really, really powerful tool because we can actually test our smart contracts and we can deploy from an IDE or a text editor that we prefer like Visual Studio code or VS code or whatever you want. And so this is going to be the same as that request and receive data tutorial, except with Node js. Hey engineers. Now we're going to learn how to build really powerful front end applications integrated with chainlink smart contracts. There's a fantastic technology out there called Truffle and it makes it really easy just to get everything in a Node JS application and for you to start coding as you would a regular Node JS application. So we're going to just dive right into it right now. So it's pretty simple. Come to the documentation page here and we're literally just going to copy paste stuff. So first we're going to install Truffle. We're going to install it globally. Npm. Install Truffle. Make sure that you have the most updated version of npm, otherwise you might get issues. So great. And then same thing. Now we're just going to copy this. Hit the little button. What it's going to do is going to make a new directory for us, going to CD into it and we're going to unbox this Smart contract kit. So this is a basically an SDK, a software development kit that has a whole bunch of boilerplate stuff for us to go ahead and start developing. So let's go ahead and do that. And this may take a few minutes to actually download. Great. And then once it's actually done downloading the box is done. We're going to to see over here we're going to have a new project. It's going to have a ton of stuff going on in here. So just to kind of give you the rundown contracts, this is where all your smart contracts are going to be. This is the same thing as Remix. Oh, you can kind of ignore this error for now. This is basically what it would look like in Remix. Obviously there's a lot more notes here for you guys so you can read and kind of figuring what it's doing out. This contract that we're doing is going to be the request and receive data tutorial in the chainlink docs. So if you haven't checked that out, be sure to do that. We also have a YouTube video coming out that's doing it in remix. So it'll be the same thing as that video just now in Node js, which is really exciting. So this is where all your smart contracts live. Migrations you don't really need to worry about, but it's going to help us put our code on chain. NodeModules is obviously node modules, Node JS scripts. These are some quick scripts basically to help us fund contracts and read and request data from contracts so that we don't have to be interacting on Remix or interacting with the contracts more directly. And then test is, this is, you know, one of the most powerful features of this is this right here. We can build these tests to make sure that all of our code does what we want it to do in relation to our smart contract. So this is a really important piece and if we jump in here, we can kind of see what it's doing. It's setting up an Ethereum chain saying, hey, these are going to be the accounts that we're going to be playing with. And before every, every test, which we can see down here and describe before every test we're going to set the link token, we're going to set an Oracle and we're going to set my contract, which is this contract here. We're going to set my contract and we're going to start running the test, right? So for example, this first test we are going to describe or say, hey, we're going to create a request without linq and we're going to literally create a request without linking. We're going to hope that it errors out when it doesn't have link and it is successful when it does. And we can run these tests. Actually right now we don't need to be connected to anything, we can just do NPN test and it's going to run this NPX truffle test. And this truffle command, it's kind of the magic command that is setting all this up, is interacting with the Ethereum chain so that we can do all this, which is really exciting and powerful. But yeah, while that's running, the rest of this is kind of more Node JS stuff. This piece is pretty important when we're doing migrations, and by migrations I mean deployments. Anytime we do a deployment, if we say we're going to do a live deployment, we're going to place those contracts on a live net. So either mainnet or testnet, depending on your RPC URL will determine that. What's an RPC URL? It's basically what connects you to an Ethereum client. So it could be a mainnet one. Oh, great. All of our test passes a mainnet one, A testnet one it really depends on. And you can find some of those, you know, either at Fuse's free one. Right. So if you use this as your RPC URL, obviously it'll be connected to Ropson. I'm actually going to use infura, but just so that you guys can see what it would look like. It's going to be a environmental variable. So you would do this export syntax, export RPC URL and then you're going to equals blah blah, blah blah, Right? And so this export command only makes this environment variable live for this terminal. So if you delete your terminal, it'll delete it. If you want to make a env file and put this export RPC piece in there, you absolutely can do that. But I would caution because I wouldn't want you to send it to your git repo and have everybody see your. Your RPC URL. And the more important bit is actually this bit over here. Process env mnemonic. So this is the 12 word seed phrase that you get when you set up your MetaMask account. If you haven't watched that video yet, definitely watch the video. So you can get that set up in MetaMask. I'm not going to show you guys, but there's a. You can actually go in here, go to like. I think it's settings. It's one of these buttons. Oh, settings. If you go to settings, you're going to reveal your seed phrase and that's going to be the mnemonic device that you're going to save. So you're also going to want to export that. So you're going to export mnemonic equals and you're going to want to put the quotes here and it's going to be like dog, cat, mouse, frog, you know, blah, blah, blah, like whatever 12 words are. So those are the two really, really important pieces and they're super important because like I said, the RPC URL is what's going to connect you to an Ethereum client. So actually be able to deploy contracts on chain, whether it's a testnet or a mainnet. Obviously if you want to do testing here, you're going to want to set it to be a testnet RPC URL. And the mnemonic device is what it's going to actually allow to interact with that wallet, with that ETH wallet. So that's why it's really important to get Metamask set up. So you have this ETH wallet that you can interact with and that's where it'll pull gas costs from it and link from and, and everything. So definitely watch that video. But yeah, this and this here. If you want to do some local testing, you can set this up so that you can do migrate dev and do like a dev environment. But we're not going to focus on that for this, for this tutorial. Great. So we're actually going to just run right into it. And we do have to edit one thing because there is a bit of a. Right now there's a bit of a glitch with the truffle box. So we just have to change this. Truffle HD wallet provider to next. Metamask updated their software recently and it caused some stuff to break. So we're just going to come in here, hit next and then run NPM install. Depending on when you watch this, this video, that bug might be gone. But for now this is what we're going to do and great. So cool. So like I said, this truffle box does a lot of different things. We want to focus on just figuring out how do we deploy contract, how do we mess with the contract, how do we do tests? And that's pretty much it. So I just showed you how to run the tests. If you want to write more tests, you come in here and you can add more context, add more stuff to do more interact with contracts, depending on what your contract actually does. Obviously this is my Contract test. So if you want to build more smart contracts or more, yeah, more contracts, you're gonna want to build tests for each one of those as well. You can use this as the rubric. So. But yeah, now what we want to do is we want to actually deploy this contract to the Ropsten testnet. I'm using, like I said, I was using export RPC URL equals I'm using a HTTPs, a Ropsten or Robson RPC URL. So this is going to deploy to a Ropsten testnet, which is really awesome that we can do it right from VS code. That's the editor that I'm using, by the way, if that wasn't apparent. And it's with a simple command NPM run, migrate, live. Now, again, this live is an important keyword. You can also do dev and that will connect to whatever you have in here. So we're going to do live though, we're going to say, hey, we want to connect to our Ropsten testnet based off the RPC URL that we gave. So we run this, we're going to take a minute or so and we're actually going to deploy nothing because there was an error. Oh, and if you run into an error like this, don't worry about it. It could just be an issue with whatever RPC URL are doing or whatever. It's testnet. It's not perfect, but yeah, we're just going to run it again and it looks like it's working this time, so that's perfect. So we are, we're doing this migration, like I said, the migration, you can think of it as the same as deploying. And the contract that I really care about is the mycontract sol, because this is the interesting one. If you haven't checked out the request and received data video, definitely check it out, definitely read the docs, see what we're doing. But basically, so what this smart contract does is it creates a request to a certain chainlink Oracle. So a single node, single job ID gives it some link pay and it requests an arbitrary URL and gets the data from that URL, which is obviously really exciting because any API in the world has a URL that we can connect to and this is how we do it. So this is kind of the code that does it all withdraw link and the whole nine yard. So we have a lot of the basic functionality here. So as it's saving this migration to the chain. And this is some interesting as well. The reason that this is a important Piece is this is kind of defining how we're deploying the contract. So we're saying, hey, if it's live, here's what we're going to do to actually deploy it and make sure it goes smoothly. So that's basically what's going on. So now we're actually deploying my contract. We have the transaction hash, we have three blocks, we have the contract address which we want to save for. I'm actually just going to put it there for a reason. I will tell you in a minute. And then we have some other stats that are really cool. Great. So now we have this actually deployed and oh so important thing, important thing is again, you know, make sure this is that Your wallet has TestNet ETH in it and TestNet Link, otherwise you know, you're not gonna be able to deploy anything. So we can actually go to Etherscan, Ropsten, Testnet, Robson and we can see this contract here just to double check. Great. It was created one minute ago by us, which is really cool that we can deploy contracts right from our VS code, right from our, you know, our Node JS application. So great. So we've deployed it. Now we have some scripts that can help us interact with this. Fun. Contracts right now is not working super well because of that bug that I was telling you about. So we're just going to fund it the manual way here, which is, which is fine. This is really quick. Anyway, so we're just going to send it, we're going to send it to Link, why not send it fast? And again, just in case you didn't know, you know, there's the Eth gas that you need to do any transaction on the Ethereum chain. There's also the chainlink gas that you need to interact with Oracles. So this is that Oracle gas that we're going to be using, the chainlink token is that chainlink gas. So once this finishes sending, our contract will actually be funded and we can go ahead and start trying to request data out of it, which again, go check out the longer video on how it works. It does it in remix. I'm going to skip over exactly what's going on in this. We're just going to deploy it and go so well, excuse me, we already deployed it. We're just going to go so great. So now we're going to do this request data script which has pretty much all the parameters that we wanted it. So we're choosing an Oracle address. You can choose any Oracle address that you want that returns this type of data we're actually returning a. What are we returning? We can see it in our contracts. It's going to be a fulfill. It's going to be a uint256. So we just need to find an Oracle that has a job that can, you know, get an arbitrary API which runs a uint256. Obviously we can go to market link again, find an oracle like this. Yep, we have the Oracle there. We have the job ID here. Right. We have the payment here, which at the moment is just one link on mainnet it would be much less. And we have our arbitrary API. We can make this anything we want and. Yeah, and then we're just going to make this, make this request. So we're going to go ahead and run the script to do this.
And.
It'S just going to be NPX Truffle. Excuse me? Truffle exec scripts request data. Oh and if you wanted to, once the funding one works, it'll just be like fundcontracts JS with the same rest of the syntax here, but we're going to do request data JX JS and then network is going to be live again. Live connector test. So this is going to do the same thing as we saw in remix of us clicking that button like request price or create request to in this case since our contract has this function create request which if you watch the other video, like I said, it's request ethprice in that other video. So we're creating the request on this contract which is perfect because that's the contract that we just deployed and we funded it. So we can actually watch on Etherscan, the transaction just came in and it's pending. And once it completes, we're going to see that show up back here. And perfect. And that's the hash right there of the completed transaction. And we can see.
Great.
It looks like it's completed here. That's fantastic. So now because we've requested this data, now we have this stored data on chain and again, if we look at the scripts here for requesting data, we can see that the URL is for the price of ETH and USD. So we want to read, write off the contract and luckily we have another script that does this. MPX Truffle exec scripts read contract network network live. And again, you know, you can edit these as you like right in here. This read contract we have. So we got an error here up same error. We can just rerun off of that. But yeah, if you have different contracts where you deploy different contracts, you're going to want to come in here and adjust these, right? So this is saying, hey, we're going to create a new variable called mc, stands for my contract. And we're going to do data dot call. So if we look in my contract, we have a variable right at the top called data. So we're just calling that. And that's what this read contracts doing. It's just, it's calling the contract, it's saying, hey, let's call that data right there. Request data obviously is a little bit more involved, but cool. So if we look down here, boom, we have the answer right there. So $228.13. Again, the blockchain doesn't do great with decimals, so all the decimals are obviously removed. We have in our contract we define times. Excuse me, not in our contract, in our request data times to be 100. So we move the decimal place over twice. And that's why we can see this right here. And that's it, guys. It's really that simple. I hope that this was helpful for you. Like I said, some of the most powerful, awesome reasons that Truffle helps out here is you can integrate this with a, with a full scale front end, back end web applications, it's Node js. You can run some of these tests so that you can actually run tests on your smart contracts both locally and on a live test net and you can configure it to be part of a, a custom test end as well. And it's just really powerful in that sense and super customizable. Well, that's it. See you guys next time. So that is it, guys. There's a lot to unpack there. There's a lot to uncover, there's a lot to do. There's a lot of really exciting opportunities. Chainlink is an open source project that's always improving. There's some really, really cool stuff coming up soon, like threshold signatures, which will help reduce costs and improve the security of the system in general. But to kind of get to there, you still need to figure out how everything works. So getting started now is, is fantastic and you'll be miles ahead of the, of the curve here. So we have tons of resources out here to help you out. I'm always around. You can ping me in discord, you can ping me on Twitter, on LinkedIn, Slack, whatever. We have a number of out of the box examples as well as examples from previous winning hackathons. We have this. Let me get out of the way here. We have these, these winning hackathon resources. I'll just leave it in the description we have. We have Hackathon resources for you to check out all the docs, tutorials, everything you guys need. Definitely, definitely, definitely jump in the Discord chat. The community is some of the happiest and most helpful people and they just all want to build really cool stuff. And we're all in there. I'm in there. And definitely check out the documentation because that's going to be the best place to start. So that's pretty much it. And what are you waiting for? Go start building some Chainlink projects. So, yeah.
Thank you, Patrick, for your workshop. I want to thank Chainlink for giving a workshop every year since the inception of SF Blocking Week. That's awesome. For those of you that are just joining us now, if you have any questions during the workshops, please feel free to ask them in chat. Our speakers will answer them accordingly. Now for our next talk, we're happy to have Tanner Allard, who leads dev Relations at Nervos. He is giving a workshop on smart contracts and rust on nerVOS, a generalized UTXO blockchain. Tanner will teach you how to build and program on top of the Nervos blockchain and capsule their smart contract framework. Tanner, the stage is all yours.
Okay, well, thank you everyone for, for coming. My name is Tanner. I'm a developer at Nervos Network. Today I'm going to be going over writing smart contracts in Rust on our layer one blockchain called Common Knowledge Base. Pretty excited. It's a new tool that came out, new support for smart contracts in Rust. All right, so before we get into actual programming, which we will have some of that today, I want to go over the paradigms and mental models that are required to develop on Nervos and then go through kind of a prescribed or suggested design and development workflow. All right, so for the Nervos programming model, the layer one blockchain, like I said, common knowledge base, the fundamental state unit is called a cell and nervous networks blockchain is, is a generalized UTXO style blockchain as opposed to Ethereum. And here you see that. Whereas on the left there's a simplified model of a UTXO that has an amount and a lock. A cell has four fields, so it has capacity, data lock and type. And we'll go into these more depth. So capacity is measured in CK bytes and a cell cannot contain more data in bytes than it has capacity. CK bytes are also the native currency on the network. So we have a storage as currency concept Here the data field is user defined data. It's just arbitrary binary data. And this is pretty powerful because it enables users to even store executable code on the blockchain. And our virtual machine is actually just a RISC V instruction set architecture based virtual machine. And so pretty much anything that any language that has a compiler with support for RISC V as a target, you can compile that code and put it on chain, which is why we can write contracts in rust. The lock field contains a verification script similar to what you'd expect at utxo. Essentially, in order to spend a cell, the lock script has to execute and succeed. And the type script is another. The type field is another script, another verification script. And it's used to validate self transformations, which essentially means the TypeScript executes on both inputs and outputs. So while the lock script verifies that an input cell can be spent, a TypeScript executes on both input and output cells. So diving into what does a script look like a bit, a bit more actually a script is, you can think of it like this map. The script itself doesn't contain data. It contains a reference to data that's stored executable code. The reason for that, one of the most obvious advantages is code reuse. If storage space itself is the native currency on the network, then it behooves us all to enable code reuse as much as possible. And having to duplicate the code, the same exact code for every cell that you may want to use with that code doesn't make a lot of sense, becomes very costly. So instead we have this reference approach. And in here you see that there are three things. There's the code hash, the arguments, and then the hash type. And we'll get into that a bit more. So the code hash can either reference the data field, ie, it can be a hash of the cell containing the executable codes data field, or it can reference the type. And either way you have this, you have a reference via code hash to a different cell on chain that is storing the executable code. And so that's why you have this, this option here for hash type as data type and that that indicates whether the code hash references the data field or the type field on the cell storing the code that needs to execute. And then of course you have arguments so you can pass, you can, based on each cell, you can control which arguments are passed to the verification script. And transactions then are, if it are the are the kind of fundamental way that you would produce a state change, right? I mean In Bitcoin, you produce transaction with inputs and outputs and the inputs are consumed and outputs are created. Right. Similarly in. Sam.
Computer science and the progress that has happened in the last century in the has given us this huge computational surplus and a great set of protocols and capabilities for creating this security in a new and more comprehensive way in cyberspace.
Truth, on the other hand, is sort.
Of taking matters into your own hands. Like with truth, it's all about interacting.
With the world directly.
Markets are about story. Great bubbles happen around stories that are really appealing, but also around stories that.
Really do change the world.
Right. The Internet bubble in the 1990s got way, way ahead of itself. But the Internet really changed about everything.
We did in the world.
And so we have. We had the same thing with crypto.
Sa. Sam. Sa. Sam. All right, well, thank you everyone for coming. My name is Tanner, I'm a developer at Nervos Network and today I'm going to be going over writing smart contracts Rust. So just a little background. Neurals Network is kind of a collection of protocols. And the one of the biggest ones we have is called Common Knowledge Base, which is a layer one blockchain, we call it CKB for short. And it's a multi asset store value blockchain. We're going to be seeing a little bit about what the multi asset part entails. Essentially, we are able to create custom assets on top of the blockchain similar to other smart contract platforms. And we're proof of work blockchain, and it's more of a UTXO style blockchain as well, so generalized programmable UTXOs. Now, the reason we're able to write smart contracts in Rust is because our virtual machine is a bit different from many different virtual machines that you may see in other chains. And it's just a virtual machine based on the RISC V instruction set architecture. So it's, you know, it's close to the hardware and because of that, anything that compiles to RISC V machine code is an available language for writing code and deploying it to chain. So today I'm going to talk about the programming model, kind of the conceptuals in the background, and then go through somewhat of a simple smart contract design and development workflow. And then we'll get started on actually developing a particular system on Nervos. And throughout the course of this, you'll be introduced to a lot of concepts as well as a particular tool that we've released recently, which is kind of a framework for building smart contracts. And we won't get into everything, like testing the smart contract, for example, because of time constraints. But I'll point you in the direction for learning more and we'll provide a link to the repo containing the code that I write today as well as the tests for that code as well. First, let's go over the programming model. And I mentioned that our state model is a generalized utxo and the fundamental state unit is we call it a cell. So on the left you see that kind of from Bitcoin utxos, they have an amount and a lock, right? And we generalize this a little bit to four different fields, capacity, data lock and type. So capacity is measured in bytes, or what we call CK bytes. And that's actually the native currency of the chain as well. So a cell has a particular capacity and it cannot occupy more bytes than the capacity indicated in its capacity field. Data is user defined data. So that can be anything. It can be executable, be executable code, or it can be any sort of state that you wish to store in the cell. And then lock is similar to what you think about with UTXO lock scripts. So in order to spend or consume cell, you need to be able to unlock it. Right? And type is an interesting addition which is another verification script. It's used to validate cell transformations. So whereas locks ensure that only the person or parties actually who can unlock the cell can spend it or consume it and therefore they operate on inputs. Purely a typescript executes on inputs and newly created outputs. Remember that because it's UTXO style chain the cells a transaction which has cells as inputs and outputs. Cells are consumed and destroyed when they're used as inputs and created when they use as outputs. So how do we get a sense of continuity of state? Well, we have these types groups that operate on inputs and outputs to verify that the state change represented by the destruction of the previous state from inputs and the creation of new state outputs is valid according to some user defined or developer defined business logic. And it's actually these lock and typescripts which constitute the usage of smart contracts on, on Nervo, CKB and lock and typescripts, well, they're called scripts. They're actually this simple data structure, this map that has three fields. So there's the code hash, the arguments passed the script and then the hash type. Okay, and basically the code hash references references a field on another cell. Either it could be the hash of the data or the hash of the type field of another cell. And the reason for this is that if you want to reuse a script, well, you have to store that script somewhere. So you store in a cell's data field, right? And we'll call that cell a code cell. And then it's potentially the case that you want to use the code stored in that cell to verify many different cells. You want to attach it to many different cells. And so these lock and type fields are actually references to some other cell that contains the executable code. So the code hash references references a cell by the hash of its data field or the hash of the type field. And that's, that's determined by a combination of the code hash itself and then the hash type, which can be either data or type. If the hash type of the lock or type fields is data, then the code hash in that, in that script structure is referencing the data field of some other cell, and for type, it's the hash of the type fields. So transactions then are three big inputs, outputs, and dependencies. Now, the function of dependencies is that, okay, you have these, you have these cells and inputs and outputs which reference other cells. And how do you find these cells? It would be pretty difficult to scan the entire chain for those every time you run a transaction, right? And so actually what happens is that the dependencies or any sort of code cell that you need, or really even cells that contain data that your transaction might need, are included in the dependencies field. And the inputs, outputs and dependencies, from the script developer's perspective are all just cells, cells with these four fields. In reality, though, just like in Bitcoin, the inputs are actually just out points. They have a, a transaction hash which references the transaction that created the input as an output, and then the index of that reference cell in the outputs of the transaction with that transaction. Hash and dependencies are similar, they're out points, but they have this additional field depth type. And the reason for this is that depth type can either be code or it can be a depth group and a depth group. All that is is a cell which actually itself references a bunch of different dependencies. And this is useful if, say, you have three or four scripts that you've developed, and maybe three of them, two or three of them are, are often used together. You can create a cell that's actually a reference, a collection of references to each of these other dependencies that you need to, and then you can just use that. So instead of including explicitly many different cells in the dependencies, if those dependencies are always going to be included together, you just create a dependency group. And you only need one cell to bring in to load in multiple different dependencies. That's kind of sophisticated, we won't really need that today. But it's just some background. And then of course these are the inputs and dependencies prior to script execution are resolved into the cells exactly like what you'd see in the outputs. So that's kind of a introduction to the state model and a bit of the program model. Now we'll go over a simple workflow for developing smart contracts. Essentially the biggest part is defining the business logic, right? This is not just in smart contract design, this is in development in general. You need to understand the system and the rules prior to writing any code, right? And so once you define a logic you kind of have two different things. You need to understand the initial state of your system once it's deployed to chain and then the verification code with that implements the business logic that your system should follow. And notice here how since the chain is generalized UTXO style, smart contracts, or what we typically call them internally are just scripts or verification scripts are not. These are not these event based scripts or contracts that live on chain which you can call and then, and then wait for them to perform some sort of side effect or update on chainstate. Truly they're just verification scripts. When they're included in a transaction, they ensure that the transaction satisfies some rule set according to whatever the code that the developer has written actually says, right? So you write the verification code, you write the initial stage and then of course the verification code cannot act on the initial state unless it's already living on chain. So once you have the initial state verification code, you deploy the code and then you deploy the initial state with its references to the verification code that you've written. The biggest part, like I said, is the business logic design. And this is kind of a simple modeling workflow that you can go, that you can go through, which is before anything you want to define the operations and queries that you want to support, then you want to design the data structures. And that's essentially a process of determining what cells you need and what the cells data fields should look like, right? And then since scripts or smart contracts themselves don't perform any sort of state updates, they merely verify transactions which describe a state transition. You need to translate your operations into transactions or transaction sets. So a transaction is analogous to an operation. So what we're going to be going through today is a simple decentralized exchange. And I remember I said that it's a multi asset chain and that means that users, developers can create their own custom assets, their own custom tokens. And we have a, we have a standard, we have a few standards, but one of them is what we call a simple UDT standard, SUDT standard that stands for just simple user defined token. You can think of it as similar to Nervos Network's version of ERC20. So it's a fungible token and we'll go over a couple of details about it. But basically the purpose of this DEX is to allow users to purchase a newly created custom token with native capacity. We can kind of think of it as an issuance lock. It's not really a DEX in the fullest sense of the word. It's just a lock script that allows users to purchase a custom token. And the operations we want, the operations relevant to this is of course minting or creating the token in the first place, issuing, exchanging, which is the act of purchasing the custom token by user. And in return the user pays the developer the token creator proportional to the amount of tokens they purchase. Right. So this conceptually depends on the UDT standard or simple user defined token standard. And so let's go over what a cell that complies with the standard looks like. And basically on the right here you see this cell and its Data field is unsigned 128bit integer. And the first, so the first series of bytes in the data field is then treated as the amount of that token, right? So if a cell, if a cell is a token cell, then the data field is treated as the, as storing the amount of that particular token in the cell. And then the type field here, of course, the code hash references the UDT code cell, which remember that's what I'm calling the a cell that contains the verification code, right? And then we have this thing called the governance lock hash. And basically the way that the user defined token standard works is that if an input cell is locked with the governance lock hash or with the lock script that hashes to this governance lock hash argument, then certain, certain verification rules are basically circumvented or foregone. And what this allows is the developer to implement really sophisticated or simple, it's really up to the developer governance logic, while not needing to modify the verification code for the token itself. And this allows for example, the person with governance permissions to mint new tokens after initial issuance, while of course preventing any user from minting new tokens, otherwise it would be infinitely inflationary. And then the lock field of the token cell is up to the user who's holding the token. And this is interesting because if you contrast it to Ethereum, where these balances of particular custom tokens are stored in a contract, that kind of acts like a registry, right? A mapping of users to their balances. This is not the case on Nervos. Rather, each, each holder of any custom token controls the cell that, that stores their, their tokens and they can, they have complete control over the, over the ownership logic. This also introduces opportunities for high levels of interoperability between different on chain systems. Because both type and lock scripts have access to the entire transaction. They can read any, any data within the transaction and then some, and then block headers as well. That's just an aside. That means that other systems, say for example, decentralized exchanges or lending protocols, can interoperate with the token standard directly by simply providing a lock script that implements the custom logic for that particular system. And users can opt in simply by changing the lock field of their cell and participate in all these different systems with whatever custom token they're holding. So there's a lot of interoperability capabilities from this design. So in our particular case for the simple Dex, which is like I said, really just an issuance lock, a way to purchase tokens, we're going to have the custom logic on the lock field and that way we can actually, when we issue a new token, we're simply placing a special lock on the token cells on the token cells lock field. And users will be able to consume that particular token cell and then create an output that transfers some of the tokens to themselves by essentially creating a new token cell with a portion of the amount held in the issuance cell. And then of course, the issuance cell, which is the cell depicted here with the DEX log, will have to have its data field modified for a decreased amount. But we can enforce things like the data field can be modified by users, but the type field cannot. We can enforce these types of rules and allow people, any user, any potential purchaser to consume this cell and therefore purchase tokens so long as this same cell is created in the outputs according to certain rules that will define. So let's look at mapping these operations like minting and issuing to transactions. And you see here that I'm just depicting the transaction with inputs and outputs. And this looks exactly like how the token standard defines issuance, where the input is any arbitrary cell, but the lock field has to have the governance lock. And that's because the token script TypeScript ensures that the inputs and outputs store some total Equal amount of the custom token. Now, of course, during issuance or minting, you're trying to create more output, you're trying to create more tokens in the output than in the input because you have zero tokens in the input, right? So we need to indicate that this is permitted because we have governance permissions over this token. So we include that cell that's locked with the governance lock and the inputs. And the governance lock can be any lock script. And then the outputs, we create a cell that's the token cell. And we can see that this is the case because the code hash has basically the, of the TypeScript, has the UDT definition, which is just another way of saying the it references the cell that contains the code that defines the verification logic for the token. And what's interesting is that in our system, since we're creating this issuance lock, this dex, the lock field of the token cell created in the outputs has the Dex lock as its code hash. And you notice there are two arguments here. One is the rate, and the reason we need a rate is that's going to indicate to us how much native capacity, native currency, which is capacity, how much capacity does each token cost? And then the payee log, which is essentially a lock hash, indicating the hash of the lock that a cell that's transferring native capacity should be locked with. So you can think of it as who is being paid for the tokens. Now in our simple example, it'll probably be the same address that created the tokens themselves, but it doesn't have to be. They could have, the token creator could have an address reserved purely for receiving payments for this, for this token. And we see here that we have three different code hashes on the different fields of the relevant cells. And that indicates to us that we need three different dependencies. We need the dex lock, the governance lock and the verification code for the four tokens themselves. Now the governance lock can be anything. And in our simple example we'll probably just use, use the default, the default lock script that people have, which is just SEC P256K1 signature verification. And then we have the Dex lock, which is what we'll be coding. And the token, the UDT definition cell is this, that implements the verification code for the user defined token standard is we could write it ourselves or we could use what's already deployed on chain, which is what we'll do. And the exchange operation is a little more sophisticated where we actually have, we actually have two inputs, right? So first, the first input is you'll notice the actual issuance cell, which is the cell containing the tokens locked with the dex lock. Right? The second input, of course, we need the user in order to send capacity in order to pay for the tokens they're acquiring, needs to consume a cell with enough capacity, needs to consume a cell, or more than one cell so that they can transfer enough capacity to the payee in order to verifiably purchase these tokens or validly purchase these tokens. And the outputs. We're going to enforce that a new issuance cell is created in the outputs in order for this transaction to succeed, that that issuance cell needs to exist on the outputs too. Right? And the type and lock fields should remain exactly the same. The only thing that should decrease is the amount of tokens stored in the issuance cells data field. We also have a the second output, which is capacity, but locked by the payee's lock. Right? And so that cell there constitutes a payment to the address the token creator has determined is the address that should receive payments in exchange for the custom token. And finally, the third output is a token cell, another one, a newly created token cell with its amount stored in the data fields as the 128, the unsigned integer. And you see that it has the type and lock fields. The type field is identical to the issuance cell because that is what is that's responsible for storing the verification logic for this particular token. The lock field, however, is different. It's not the dex lock, it's whatever lock the user locked wants to attach to it because the user owns it. Right. And we'll have to enforce rules about the fact that the data in the output issuance cell is equal to the data in the input issuance cell minus the amount of tokens purchased, for example. These are all rules that we'll have to think about. So just to recap, what this state change is doing is we are decreasing the amount in the issuance cell between the input and output. So the purchaser is making this change. Then capacity, which is once again the native currency, is sent to the the recipient who should be receiving payments for purchasing tokens. And then the custom token, some of the custom tokens proportional to how much capacity we've paid for is then sent to us, basically. Or if we're the user, if we're the purchaser, then we create this output and send some custom tokens to ourselves as well. So that constitutes what the operations will look like for both issuing and exchanging. And because of that, we understand what our initial state is going to be. It's going to be that, it's going to be that particular issuance cell which is just a token cell with the Dex lock. Right. And in order to go from this to an actual on chain system, well, first we need to write the. We need to either ensure that these dependency scripts already exist on chain, or write them ourselves and then deploy them to chain. And after that we'll deploy the initial state. So now we'll get into some of the actual smart contract development practices. And what we'll be doing is using a new tool that Nervos release called Capsule. Capsule is a framework for developing scripts in Rust. So you are provided with boilerplate. You can create projects and you can then develop scripts, you can write tests for those scripts and you can also deploy those scripts to a local developer chain, testnet or mainnet, all from Capsule. And Capsule creates a couple different modules for you and we'll see this itself, but you basically you'll have the build for the contracts that you actually compile the contracts module where you actually develop your contracts and then the tests. Okay, so I'm just going to pull up Capsule now and before we go into developing, I want to show you some useful resources and links that you can use. So capsule is GitHub on GitHub nervous network capsule. It has a great wiki here that walks through setting it up and actually building or implementing the user defined token contract. So it's a contract that's compliant with the user defined token standard. And what's actually interesting here is that Capsule uses these other libraries and the Rust used in Capsule is actually no standard rust. So kind of think of it like embedded system systems development. However, we provide CKB something like a library called CKB Standard and CKB types which allow for the use of richer data structures and system calls for this no standard rust. And the documentation with these is very useful. I'll probably have to refer to it myself during, during this little demo here, but we see that CKB Standard has these various, has these various modules and the two will be. The three we'll be using the most is CKB constants, High Level and syscalls. Now syscalls provide support for all the system calls that a script can execute, right? So if we want to load a cell or we want to load a script, load a transaction, that type of thing. And then High level are kind of these nice wrappers around, around the system calls to provide some, an easier interface and some, some additional functionality. Right. So technically all of the things included in High level of the functions. You can, you can achieve all of this functionality without using the high level module using purely the system calls and syscalls, but it's easier to use this one needed. So then we have that and now then we also have CKB types and the bulk of it is in the PACT module which provides these data structures out of the box for all of these different types of data that the, that the system calls and whatnot might return. So if we just go to Outpoint, for example, we can load in an out point and you know that as a, at the system call level that may be just a series of bytes, but we can initialize an out point structure from those bytes. And all of the sudden we have access to these simple methods that can allow us to extract the transaction hash in the index, for example. Okay, So I'm just going to pull up the code editor, we'll get started on actually coding some things up. And really due to constraints here, we'll just be sketching out a skeleton of the project, get to some of the functionality. But I'll provide a link afterward so that you can, you can get into more depth on developing the script and writing tests and seeing the full code that results from it. Okay, So I have my code editor up here and I have Capsule installed already. Capsule is really easy to install and you can follow the GitHub repo wiki nervous network slash Capsule for that. But I'm just going to create a new project Unitize Workshop. It already exists, so I will create one called simpledex and that's just a Capsule new command and it's going to create all these things for us. So it's creating a couple packages, the actual binary binary package and the tests as well. So we'll go to that now. And. Frankly I don't usually use this text editor, so I forget how to open or enable the command line options. So I will just go this way. Okay, so we have this, we have our structure. Skip that for now. We have our structure here, our project structure. So there's builds, that's where the contracts we actually compiler and where we're going to be working is really inside the contracts in the main rs. So like I said, it's no standard. So there's a bunch of setup here for using Core instead of standard library. And then we have these, our imports for our actual, for our CKB specific libraries and we can change these as well. And this is just the template that Capsule sets up for you. And then this we can ignore right this really just ensures that the system API of the virtual machine is, is followed. And really it's going to call this, it's going to call this main function which is defined below. We also have this error enum here where we can define our custom errors and it'll just work, right? So this is the main function. You can see it's remove below examples and write your code here. So this is where we get into where we'll write our code and execute it. So I'm going to get a terminal and running to make this a little bit bigger. Ok, so what's one thing that we want to, what's one thing that we want to basically ensure? Remember we have three outputs in our, in our expected exchange, right? So the first output is the issuance cell. The second output here is the, is the payment cell. The third output is of course the user's custom token cell that they purchased, right? So of course we need to enforce a certain set of rules on these things, right? And before we do any of that, we really need to, we really need to be able to load in the issuance cells and ensure the rate, right? And so that's what we'll do is we will focus on loading in the issuance cells or certain, certain parts of them at least. Right? And so let's do we also want to load in the arguments, right, because the arguments contain the payee lock and the rate. So that's what, that's what we'll, that's what we'll do. So we see that there's already this system call for loading the scripts and we unpack it into bytes and bytes. We can place this data structure but we can compare them with vectors of bytes or arrays of bytes, etc. So there are two arguments here, two arguments. The first is the rate, which is, which denotes capacity, right? And capacity or CK bytes is a one size 64 bit integer. And the second argument is the payee lock. And the payee lock is going to be a 32 byte hash of a lock field, right? So because of that I'm going to, going to define two, two things here. Rate bytes, which is just going to be a byte array. It's a 64 bit number, so it's going to be 8 bytes long. And then I'm going to do the same thing for the payee lock. And this is basically I'm just trying to get these into their own, their own data structures outside of the ARGS bytes, which is just easier. Not necessarily the best way always, but easier to Reason about as we kind of develop a prototype here and we can of course from these, from these arrays we can copy from slice, which is a method. So we can copy the contents of a slice from somewhere else to these arrays. So that's what I'm going to do. And we want the first 8 bytes from the args and then for paylock bytes we want basically the rest of them right. Now. Right now this contract is assuming that those are the only two arguments and that's the assumption we're going to make for this particular prototype. And then it's in the byorder for this CKB virtual machine is in Little Endian. So we're actually going to make the rate itself. Remember it's a U64 from the bytes of the rate bytes and we can just pass rate bytes in. We won't need it again. It's only necessary to get this rate. So now we have the rate and the paylock that's just. That's just an array of bytes. We don't really need to do anything else to it after the that now we need to. Let's see what do we want to check first? Let's check that the. Let's check that the. We're loading the issuance cells because we want to load in the issuance cells and then from the difference in the issuance cells amount field that will allow us to get the. To get the actual amount that the user has to pay. So we will say issuance cells equal load issuance cells and notice that this returns a result. This, this main method returns results. So we're just going to. Just going to make the error handling simple. And so once we have load issuance cells, which is just a hypothetical function, we don't have it yet. Once we have those issuance cells, we need to calculate the minimum payment. So. And the minimum payment will need two things. It'll need the issuance cells so that it can check the difference in the amount fields and it will also need the rate so it can use the rate and the amount and the amount that the user has purchased in order to determine the final fee that are payment that the user must provide. So we'll calculate min payment. This is the second function we don't yet have and that's going to take the rate and G64 it's like it's a copy, it's a copy type. So if we pass it in, we don't have to worry about any sort of ownership issues necessarily. I'm pretty sure I actually have to check the documentation to ensure. But yeah, it's primitive type so it should be copy. And then we would need the issuance cells, right, which are going to be custom probably for making it easier. We'll have this load issuance else be probably a tuple of two custom structures for us. And that's also going to return error error handling. And then once we know the minimum payment, we probably want to get the payment amount. Now in order to get the payment amount that the user actually paid, we will probably need to check which outputs are locked with the particular pay lock. Right, with this lock and check that the capacity, the sum total capacity of those cells is equal to this is at least equal to this minimum payment, if not greater. You're always allowed to pay more, right? But you can't pay less than the minimum. So we'll say that let payment amount. And that will take the reference to paylock rights. And then the big logic that we want is basically if the minimum payment is greater than the payment amount, we need to return an error. So we return an error and we're going to use our custom errors here. Payment not enough. Now, this error doesn't exist yet, but what we can do is we can scroll up and just add here. Now that error is valid. It's valid error code. Okay, so let's focus on loading the issuance cells and that's probably all we'll have time to get to. But like I said, I'll provide the GitHub link to see all of this code. So what does load issuance cells take for an argument? Nothing. Okay. And load issuance cells, it's going to return a result, we know that. And it's going to return, like I said, a tuple of issuance, one for input, one for output. I'm probably going to define this custom type here and then return an error. I actually have to define the structure for this custom structure of my issuance cell. Right? And the issuance cell, let's define it here, has a couple different things. So we want to indicate if it's from the inputs or outputs. So it's going to have this source and the CKV constants defines this enum of source which can indicate an input or output. We of course have to, we have to include that here, right? So that's CKB constants. So we're going to include those and that allows us, that'll bring in this source enum for us. Now the data is going to be a vector of bytes, right? So we're just going to Say vector bytes, it's going to have a lock hash too. Right. And we need that because we want to ensure that the lock hash, lock hash doesn't change. The data is going to contain the amounts which we'll want in order to compare and determine the minimum payment amount and the lock hash. Well, we need to ensure that the issuance cells, the lock hashes, remain the same. So, and that's going to be we can just make that statically sized array because the hash is going to be 32 bytes long, the index. So we might need to access these issuance cells later or access other fields in them through other syscalls. So it's nice to have the index of the cell in its, in the inputs or outputs, use size and then finally its capacity. Right. We're going to want to make sure that the capacity doesn't change. Even though a purchaser is purchasing this issuance cell, wanna make sure the capacity hasn't changed. Okay, so in order to load the issuance cell, how do we know if a cell is an issuance cell? Well, essentially it's going to have a special lock hash. Right. And a script has access to everything in a transaction, including itself. So we can use this cool method syscall called loadscript hash, which will return the script hash. And that's a high level method. So we need to bring it into scope there. And I'm just going to refer to the documentation and check if that returns an array or probably an array of bytes. Yep, it returns a static sized array.










