github.com/kaituanwang/hyperledger@v2.0.1+incompatible/docs/source/developapps/smartcontract.md (about) 1 # Smart Contract Processing 2 3 **Audience**: Architects, Application and smart contract developers 4 5 At the heart of a blockchain network is a smart contract. In PaperNet, the code 6 in the commercial paper smart contract defines the valid states for commercial 7 paper, and the transaction logic that transition a paper from one state to 8 another. In this topic, we're going to show you how to implement a real world 9 smart contract that governs the process of issuing, buying and redeeming 10 commercial paper. 11 12 We're going to cover: 13 14 * [What is a smart contract and why it's important](#smart-contract) 15 * [How to define a smart contract](#contract-class) 16 * [How to define a transaction](#transaction-definition) 17 * [How to implement a transaction](#transaction-logic) 18 * [How to represent a business object in a smart contract](#representing-an-object) 19 * [How to store and retrieve an object in the ledger](#access-the-ledger) 20 21 If you'd like, you can [download the sample](../install.html) and even [run it 22 locally](../tutorial/commercial_paper.html). It is written in JavaScript and Java, but 23 the logic is quite language independent, so you'll easily be able to see what's 24 going on! (The sample will become available for Go as well.) 25 26 ## Smart Contract 27 28 A smart contract defines the different states of a business object and governs 29 the processes that move the object between these different states. Smart 30 contracts are important because they allow architects and smart contract 31 developers to define the key business processes and data that are shared across 32 the different organizations collaborating in a blockchain network. 33 34 In the PaperNet network, the smart contract is shared by the different network 35 participants, such as MagnetoCorp and DigiBank. The same version of the smart 36 contract must be used by all applications connected to the network so that they 37 jointly implement the same shared business processes and data. 38 39 ## Implementation Languages 40 41 There are two runtimes that are supported, the Java Virtual Machine and Node.js. This 42 gives the opportunity to use one of JavaScript, TypeScript, Java or any other language 43 that can run on one of these supported runtimes. 44 45 In Java and TypeScript, annotations or decorators are used to provide information about 46 the smart contract and it's structure. This allows for a richer development experience --- 47 for example, author information or return types can be enforced. Within JavaScript, 48 conventions must be followed, therefore, there are limitations around what can be 49 determined automatically. 50 51 Examples here are given in both JavaScript and Java. 52 53 ## Contract class 54 55 A copy of the PaperNet commercial paper smart contract is contained in a single 56 file. View it with your browser, or open it in your favorite editor if you've downloaded it. 57 - `papercontract.js` - [JavaScript version](https://github.com/hyperledger/fabric-samples/blob/master/commercial-paper/organization/magnetocorp/contract/lib/papercontract.js) 58 - `CommercialPaperContract.java` - [Java version](https://github.com/hyperledger/fabric-samples/blob/master/commercial-paper/organization/magnetocorp//contract-java/src/main/java/org/example/CommercialPaperContract.java) 59 60 61 You may notice from the file path that this is MagnetoCorp's copy of the smart 62 contract. MagnetoCorp and DigiBank must agree on the version of the smart contract 63 that they are going to use. For now, it doesn't matter which organization's copy 64 you use, they are all the same. 65 66 Spend a few moments looking at the overall structure of the smart contract; 67 notice that it's quite short! Towards the top of the file, you'll see 68 that there's a definition for the commercial paper smart contract: 69 <details open="true"> 70 <summary>JavaScript</summary> 71 ```JavaScript 72 class CommercialPaperContract extends Contract {...} 73 ``` 74 </details> 75 76 <details> 77 <summary>Java</summary> 78 ```Java 79 @Contract(...) 80 @Default 81 public class CommercialPaperContract implements ContractInterface {...} 82 ``` 83 </details> 84 85 86 The `CommercialPaperContract` class contains the transaction definitions for commercial paper -- **issue**, **buy** 87 and **redeem**. It's these transactions that bring commercial papers into 88 existence and move them through their lifecycle. We'll examine these 89 [transactions](#transaction-definition) soon, but for now notice for JavaScript, that the 90 `CommericalPaperContract` extends the Hyperledger Fabric `Contract` 91 [class](https://hyperledger.github.io/fabric-chaincode-node/{BRANCH}/api/fabric-contract-api.Contract.html). 92 93 With Java, the class must be decorated with the `@Contract(...)` annotation. This provides the opportunity 94 to supply additional information about the contract, such as license and author. The `@Default()` annotation 95 indicates that this contract class is the default contract class. Being able to mark a contract class as the 96 default contract class is useful in some smart contracts which have multiple contract classes. 97 98 If you are using a TypeScript implementation, there are similar `@Contract(...)` annotations that fulfill the same purpose as in Java. 99 100 For more information on the available annotations, consult the available API documentation: 101 * [API documentation for Java smart contracts](https://hyperledger.github.io/fabric-chaincode-java/) 102 * [API documentation for Node.js smart contracts](https://hyperledger.github.io/fabric-chaincode-node/) 103 104 These classes, annotations, and the `Context` class, were brought into scope earlier: 105 106 <details open="true"> 107 <summary>JavaScript</summary> 108 ```JavaScript 109 const { Contract, Context } = require('fabric-contract-api'); 110 ``` 111 </details> 112 113 <details> 114 <summary>Java</summary> 115 ```Java 116 import org.hyperledger.fabric.contract.Context; 117 import org.hyperledger.fabric.contract.ContractInterface; 118 import org.hyperledger.fabric.contract.annotation.Contact; 119 import org.hyperledger.fabric.contract.annotation.Contract; 120 import org.hyperledger.fabric.contract.annotation.Default; 121 import org.hyperledger.fabric.contract.annotation.Info; 122 import org.hyperledger.fabric.contract.annotation.License; 123 import org.hyperledger.fabric.contract.annotation.Transaction; 124 ``` 125 </details> 126 127 128 Our commercial paper contract will use built-in features of these classes, such 129 as automatic method invocation, a 130 [per-transaction context](./transactioncontext.html), 131 [transaction handlers](./transactionhandler.html), and class-shared state. 132 133 Notice also how the JavaScript class constructor uses its 134 [superclass](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/super) 135 to initialize itself with an explicit [contract name](./contractname.html): 136 137 ```JavaScript 138 constructor() { 139 super('org.papernet.commercialpaper'); 140 } 141 ``` 142 143 With the Java class, the constructor is blank as the explicit contract name can be specified in the `@Contract()` annotation. If it's absent, then the name of the class is used. 144 145 Most importantly, `org.papernet.commercialpaper` is very descriptive -- this smart 146 contract is the agreed definition of commercial paper for all PaperNet 147 organizations. 148 149 Usually there will only be one smart contract per file -- contracts tend to have 150 different lifecycles, which makes it sensible to separate them. However, in some 151 cases, multiple smart contracts might provide syntactic help for applications, 152 e.g. `EuroBond`, `DollarBond`, `YenBond`, but essentially provide the same 153 function. In such cases, smart contracts and transactions can be disambiguated. 154 155 ## Transaction definition 156 157 Within the class, locate the **issue** method. 158 <details open="true"> 159 <summary>JavaScript</summary> 160 ```JavaScript 161 async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime, faceValue) {...} 162 ``` 163 </details> 164 165 <details> 166 <summary>Java</summary> 167 ```Java 168 @Transaction 169 public CommercialPaper issue(CommercialPaperContext ctx, 170 String issuer, 171 String paperNumber, 172 String issueDateTime, 173 String maturityDateTime, 174 int faceValue) {...} 175 ``` 176 </details> 177 178 The Java annotation `@Transaction` is used to mark this method as a transaction definition; TypeScript has an equivalent annotation. 179 180 This function is given control whenever this contract is called to `issue` a 181 commercial paper. Recall how commercial paper 00001 was created with the 182 following transaction: 183 184 ``` 185 Txn = issue 186 Issuer = MagnetoCorp 187 Paper = 00001 188 Issue time = 31 May 2020 09:00:00 EST 189 Maturity date = 30 November 2020 190 Face value = 5M USD 191 ``` 192 193 We've changed the variable names for programming style, but see how these 194 properties map almost directly to the `issue` method variables. 195 196 The `issue` method is automatically given control by the contract whenever an 197 application makes a request to issue a commercial paper. The transaction 198 property values are made available to the method via the corresponding 199 variables. See how an application submits a transaction using the Hyperledger 200 Fabric SDK in the [application](./application.html) topic, using a sample 201 application program. 202 203 You might have noticed an extra variable in the **issue** definition -- `ctx`. 204 It's called the [**transaction context**](./transactioncontext.html), and it's 205 always first. By default, it maintains both per-contract and per-transaction 206 information relevant to [transaction logic](#transaction-logic). For example, it 207 would contain MagnetoCorp's specified transaction identifier, a MagnetoCorp 208 issuing user's digital certificate, as well as access to the ledger API. 209 210 See how the smart contract extends the default transaction context by 211 implementing its own `createContext()` method rather than accepting the 212 default implementation: 213 214 <details open="true"> 215 <summary>JavaScript</summary> 216 ```JavaScript 217 createContext() { 218 return new CommercialPaperContext() 219 } 220 ``` 221 </details> 222 223 <details> 224 <summary>Java</summary> 225 ```Java 226 @Override 227 public Context createContext(ChaincodeStub stub) { 228 return new CommercialPaperContext(stub); 229 } 230 ``` 231 </details> 232 233 234 This extended context adds a custom property `paperList` to the defaults: 235 <details open="true"> 236 <summary>JavaScript</summary> 237 ```JavaScript 238 class CommercialPaperContext extends Context { 239 240 constructor() { 241 super(); 242 // All papers are held in a list of papers 243 this.paperList = new PaperList(this); 244 } 245 ``` 246 </details> 247 248 <details> 249 <summary>Java</summary> 250 ```Java 251 class CommercialPaperContext extends Context { 252 public CommercialPaperContext(ChaincodeStub stub) { 253 super(stub); 254 this.paperList = new PaperList(this); 255 } 256 public PaperList paperList; 257 } 258 ``` 259 </details> 260 261 We'll soon see how `ctx.paperList` can be subsequently used to help store and 262 retrieve all PaperNet commercial papers. 263 264 To solidify your understanding of the structure of a smart contract transaction, 265 locate the **buy** and **redeem** transaction definitions, and see if you can 266 see how they map to their corresponding commercial paper transactions. 267 268 The **buy** transaction: 269 270 ``` 271 Txn = buy 272 Issuer = MagnetoCorp 273 Paper = 00001 274 Current owner = MagnetoCorp 275 New owner = DigiBank 276 Purchase time = 31 May 2020 10:00:00 EST 277 Price = 4.94M USD 278 ``` 279 280 <details open="true"> 281 <summary>JavaScript</summary> 282 ```JavaScript 283 async buy(ctx, issuer, paperNumber, currentOwner, newOwner, price, purchaseTime) {...} 284 ``` 285 </details> 286 287 <details> 288 <summary>Java</summary> 289 ```Java 290 @Transaction 291 public CommercialPaper buy(CommercialPaperContext ctx, 292 String issuer, 293 String paperNumber, 294 String currentOwner, 295 String newOwner, 296 int price, 297 String purchaseDateTime) {...} 298 ``` 299 </details> 300 301 The **redeem** transaction: 302 303 ``` 304 Txn = redeem 305 Issuer = MagnetoCorp 306 Paper = 00001 307 Redeemer = DigiBank 308 Redeem time = 31 Dec 2020 12:00:00 EST 309 ``` 310 311 <details open="true"> 312 <summary>JavaScript</summary> 313 ```JavaScript 314 async redeem(ctx, issuer, paperNumber, redeemingOwner, redeemDateTime) {...} 315 ``` 316 </details> 317 318 <details> 319 <summary>Java</summary> 320 ```Java 321 @Transaction 322 public CommercialPaper redeem(CommercialPaperContext ctx, 323 String issuer, 324 String paperNumber, 325 String redeemingOwner, 326 String redeemDateTime) {...} 327 ``` 328 </details> 329 330 In both cases, observe the 1:1 correspondence between the commercial paper 331 transaction and the smart contract method definition. 332 333 All of the JavaScript functions use the `async` and `await` 334 [keywords](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function) which allow JavaScript functions to be treated as if they were synchronous function calls. 335 336 337 ## Transaction logic 338 339 Now that you've seen how contracts are structured and transactions are defined, 340 let's focus on the logic within the smart contract. 341 342 Recall the first **issue** transaction: 343 344 ``` 345 Txn = issue 346 Issuer = MagnetoCorp 347 Paper = 00001 348 Issue time = 31 May 2020 09:00:00 EST 349 Maturity date = 30 November 2020 350 Face value = 5M USD 351 ``` 352 353 It results in the **issue** method being passed control: 354 <details open="true"> 355 <summary>JavaScript</summary> 356 ```JavaScript 357 async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime, faceValue) { 358 359 // create an instance of the paper 360 let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue); 361 362 // Smart contract, rather than paper, moves paper into ISSUED state 363 paper.setIssued(); 364 365 // Newly issued paper is owned by the issuer 366 paper.setOwner(issuer); 367 368 // Add the paper to the list of all similar commercial papers in the ledger world state 369 await ctx.paperList.addPaper(paper); 370 371 // Must return a serialized paper to caller of smart contract 372 return paper.toBuffer(); 373 } 374 ``` 375 </details> 376 377 <details> 378 <summary>Java</summary> 379 ```Java 380 @Transaction 381 public CommercialPaper issue(CommercialPaperContext ctx, 382 String issuer, 383 String paperNumber, 384 String issueDateTime, 385 String maturityDateTime, 386 int faceValue) { 387 388 System.out.println(ctx); 389 390 // create an instance of the paper 391 CommercialPaper paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, 392 faceValue,issuer,""); 393 394 // Smart contract, rather than paper, moves paper into ISSUED state 395 paper.setIssued(); 396 397 // Newly issued paper is owned by the issuer 398 paper.setOwner(issuer); 399 400 System.out.println(paper); 401 // Add the paper to the list of all similar commercial papers in the ledger 402 // world state 403 ctx.paperList.addPaper(paper); 404 405 // Must return a serialized paper to caller of smart contract 406 return paper; 407 } 408 ``` 409 </details> 410 411 412 The logic is simple: take the transaction input variables, create a new 413 commercial paper `paper`, add it to the list of all commercial papers using 414 `paperList`, and return the new commercial paper (serialized as a buffer) as the 415 transaction response. 416 417 See how `paperList` is retrieved from the transaction context to provide access 418 to the list of commercial papers. `issue()`, `buy()` and `redeem()` continually 419 re-access `ctx.paperList` to keep the list of commercial papers up-to-date. 420 421 The logic for the **buy** transaction is a little more elaborate: 422 <details open="true"> 423 <summary>JavaScript</summary> 424 ```JavaScript 425 async buy(ctx, issuer, paperNumber, currentOwner, newOwner, price, purchaseDateTime) { 426 427 // Retrieve the current paper using key fields provided 428 let paperKey = CommercialPaper.makeKey([issuer, paperNumber]); 429 let paper = await ctx.paperList.getPaper(paperKey); 430 431 // Validate current owner 432 if (paper.getOwner() !== currentOwner) { 433 throw new Error('Paper ' + issuer + paperNumber + ' is not owned by ' + currentOwner); 434 } 435 436 // First buy moves state from ISSUED to TRADING 437 if (paper.isIssued()) { 438 paper.setTrading(); 439 } 440 441 // Check paper is not already REDEEMED 442 if (paper.isTrading()) { 443 paper.setOwner(newOwner); 444 } else { 445 throw new Error('Paper ' + issuer + paperNumber + ' is not trading. Current state = ' +paper.getCurrentState()); 446 } 447 448 // Update the paper 449 await ctx.paperList.updatePaper(paper); 450 return paper.toBuffer(); 451 } 452 ``` 453 </details> 454 455 <details> 456 <summary>Java</summary> 457 ```Java 458 @Transaction 459 public CommercialPaper buy(CommercialPaperContext ctx, 460 String issuer, 461 String paperNumber, 462 String currentOwner, 463 String newOwner, 464 int price, 465 String purchaseDateTime) { 466 467 // Retrieve the current paper using key fields provided 468 String paperKey = State.makeKey(new String[] { paperNumber }); 469 CommercialPaper paper = ctx.paperList.getPaper(paperKey); 470 471 // Validate current owner 472 if (!paper.getOwner().equals(currentOwner)) { 473 throw new RuntimeException("Paper " + issuer + paperNumber + " is not owned by " + currentOwner); 474 } 475 476 // First buy moves state from ISSUED to TRADING 477 if (paper.isIssued()) { 478 paper.setTrading(); 479 } 480 481 // Check paper is not already REDEEMED 482 if (paper.isTrading()) { 483 paper.setOwner(newOwner); 484 } else { 485 throw new RuntimeException( 486 "Paper " + issuer + paperNumber + " is not trading. Current state = " + paper.getState()); 487 } 488 489 // Update the paper 490 ctx.paperList.updatePaper(paper); 491 return paper; 492 } 493 ``` 494 </details> 495 496 See how the transaction checks `currentOwner` and that `paper` is `TRADING` 497 before changing the owner with `paper.setOwner(newOwner)`. The basic flow is 498 simple though -- check some pre-conditions, set the new owner, update the 499 commercial paper on the ledger, and return the updated commercial paper 500 (serialized as a buffer) as the transaction response. 501 502 Why don't you see if you can understand the logic for the **redeem** 503 transaction? 504 505 ## Representing an object 506 507 We've seen how to define and implement the **issue**, **buy** and **redeem** 508 transactions using the `CommercialPaper` and `PaperList` classes. Let's end 509 this topic by seeing how these classes work. 510 511 Locate the `CommercialPaper` class: 512 513 <details open="true"> 514 <summary>JavaScript</summary> 515 In the 516 [paper.js file](https://github.com/hyperledger/fabric-samples/blob/master/commercial-paper/organization/magnetocorp/contract/lib/paper.js): 517 518 ```JavaScript 519 class CommercialPaper extends State {...} 520 ``` 521 </details> 522 523 <details> 524 <summary>Java</summary> 525 In the [CommercialPaper.java file](https://github.com/hyperledger/fabric-samples/blob/release-1.4/commercial-paper/organization/magnetocorp/contract-java/src/main/java/org/example/CommercialPaper.java): 526 527 528 ```Java 529 @DataType() 530 public class CommercialPaper extends State {...} 531 ``` 532 </details> 533 534 535 This class contains the in-memory representation of a commercial paper state. 536 See how the `createInstance` method initializes a new commercial paper with the 537 provided parameters: 538 539 <details open="true"> 540 <summary>JavaScript</summary> 541 ```JavaScript 542 static createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue) { 543 return new CommercialPaper({ issuer, paperNumber, issueDateTime, maturityDateTime, faceValue }); 544 } 545 ``` 546 </details> 547 548 <details> 549 <summary>Java</summary> 550 ```Java 551 public static CommercialPaper createInstance(String issuer, String paperNumber, String issueDateTime, 552 String maturityDateTime, int faceValue, String owner, String state) { 553 return new CommercialPaper().setIssuer(issuer).setPaperNumber(paperNumber).setMaturityDateTime(maturityDateTime) 554 .setFaceValue(faceValue).setKey().setIssueDateTime(issueDateTime).setOwner(owner).setState(state); 555 } 556 ``` 557 </details> 558 559 Recall how this class was used by the **issue** transaction: 560 561 <details open="true"> 562 <summary>JavaScript</summary> 563 ```JavaScript 564 let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, faceValue); 565 ``` 566 </details> 567 568 <details> 569 <summary>Java</summary> 570 ```Java 571 CommercialPaper paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime, maturityDateTime, 572 faceValue,issuer,""); 573 ``` 574 </details> 575 576 See how every time the issue transaction is called, a new in-memory instance of 577 a commercial paper is created containing the transaction data. 578 579 A few important points to note: 580 581 * This is an in-memory representation; we'll see 582 [later](#accessing-the-ledger) how it appears on the ledger. 583 584 585 * The `CommercialPaper` class extends the `State` class. `State` is an 586 application-defined class which creates a common abstraction for a state. 587 All states have a business object class which they represent, a composite 588 key, can be serialized and de-serialized, and so on. `State` helps our code 589 be more legible when we are storing more than one business object type on 590 the ledger. Examine the `State` class in the `state.js` 591 [file](https://github.com/hyperledger/fabric-samples/blob/master/commercial-paper/organization/magnetocorp/contract/ledger-api/state.js). 592 593 594 * A paper computes its own key when it is created -- this key will be used 595 when the ledger is accessed. The key is formed from a combination of 596 `issuer` and `paperNumber`. 597 598 ```JavaScript 599 constructor(obj) { 600 super(CommercialPaper.getClass(), [obj.issuer, obj.paperNumber]); 601 Object.assign(this, obj); 602 } 603 ``` 604 605 606 * A paper is moved to the `ISSUED` state by the transaction, not by the paper 607 class. That's because it's the smart contract that governs the lifecycle 608 state of the paper. For example, an `import` transaction might create a new 609 set of papers immediately in the `TRADING` state. 610 611 The rest of the `CommercialPaper` class contains simple helper methods: 612 613 ```JavaScript 614 getOwner() { 615 return this.owner; 616 } 617 ``` 618 619 Recall how methods like this were used by the smart contract to move the 620 commercial paper through its lifecycle. For example, in the **redeem** 621 transaction we saw: 622 623 ```JavaScript 624 if (paper.getOwner() === redeemingOwner) { 625 paper.setOwner(paper.getIssuer()); 626 paper.setRedeemed(); 627 } 628 ``` 629 630 ## Access the ledger 631 632 Now locate the `PaperList` class in the `paperlist.js` 633 [file](https://github.com/hyperledger/fabric-samples/blob/master/commercial-paper/organization/magnetocorp/contract/lib/paperlist.js): 634 635 ```JavaScript 636 class PaperList extends StateList { 637 ``` 638 639 This utility class is used to manage all PaperNet commercial papers in 640 Hyperledger Fabric state database. The PaperList data structures are described 641 in more detail in the [architecture topic](./architecture.html). 642 643 Like the `CommercialPaper` class, this class extends an application-defined 644 `StateList` class which creates a common abstraction for a list of states -- in 645 this case, all the commercial papers in PaperNet. 646 647 The `addPaper()` method is a simple veneer over the `StateList.addState()` 648 method: 649 650 ```JavaScript 651 async addPaper(paper) { 652 return this.addState(paper); 653 } 654 ``` 655 656 You can see in the `StateList.js` 657 [file](https://github.com/hyperledger/fabric-samples/blob/master/commercial-paper/organization/magnetocorp/contract/ledger-api/statelist.js) 658 how the `StateList` class uses the Fabric API `putState()` to write the 659 commercial paper as state data in the ledger: 660 661 ```JavaScript 662 async addState(state) { 663 let key = this.ctx.stub.createCompositeKey(this.name, state.getSplitKey()); 664 let data = State.serialize(state); 665 await this.ctx.stub.putState(key, data); 666 } 667 ``` 668 669 Every piece of state data in a ledger requires these two fundamental elements: 670 671 * **Key**: `key` is formed with `createCompositeKey()` using a fixed name and 672 the key of `state`. The name was assigned when the `PaperList` object was 673 constructed, and `state.getSplitKey()` determines each state's unique key. 674 675 676 * **Data**: `data` is simply the serialized form of the commercial paper 677 state, created using the `State.serialize()` utility method. The `State` 678 class serializes and deserializes data using JSON, and the State's business 679 object class as required, in our case `CommercialPaper`, again set when the 680 `PaperList` object was constructed. 681 682 683 Notice how a `StateList` doesn't store anything about an individual state or the 684 total list of states -- it delegates all of that to the Fabric state database. 685 This is an important design pattern -- it reduces the opportunity for [ledger 686 MVCC collisions](../readwrite.html) in Hyperledger Fabric. 687 688 The StateList `getState()` and `updateState()` methods work in similar ways: 689 690 ```JavaScript 691 async getState(key) { 692 let ledgerKey = this.ctx.stub.createCompositeKey(this.name, State.splitKey(key)); 693 let data = await this.ctx.stub.getState(ledgerKey); 694 let state = State.deserialize(data, this.supportedClasses); 695 return state; 696 } 697 ``` 698 699 ```JavaScript 700 async updateState(state) { 701 let key = this.ctx.stub.createCompositeKey(this.name, state.getSplitKey()); 702 let data = State.serialize(state); 703 await this.ctx.stub.putState(key, data); 704 } 705 ``` 706 707 See how they use the Fabric APIs `putState()`, `getState()` and 708 `createCompositeKey()` to access the ledger. We'll expand this smart contract 709 later to list all commercial papers in paperNet -- what might the method look 710 like to implement this ledger retrieval? 711 712 That's it! In this topic you've understood how to implement the smart contract 713 for PaperNet. You can move to the next sub topic to see how an application 714 calls the smart contract using the Fabric SDK. 715 716 <!--- Licensed under Creative Commons Attribution 4.0 International License 717 https://creativecommons.org/licenses/by/4.0/ -->