Skip to content

Commit

Permalink
Merge pull request #35 from onflow/sainati/access-all-formatting
Browse files Browse the repository at this point in the history
Improve formatting of access modifiers in documentation
  • Loading branch information
dsainati1 committed Dec 22, 2023
2 parents 26c68e8 + 89dc9c7 commit 2d3ae7f
Show file tree
Hide file tree
Showing 33 changed files with 1,467 additions and 665 deletions.
64 changes: 44 additions & 20 deletions versioned_docs/version-1.0/anti-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ which provides the opportunity for bad actors to take advantage of.
// They could deploy the contract with an Ethereum-style access control list functionality
access(all) fun transferNFT(id: UInt64, owner: auth(Storage) &Account) {
access(all)
fun transferNFT(id: UInt64, owner: auth(Storage) &Account) {
assert(owner(id) == owner.address)
transfer(id)
Expand All @@ -42,7 +43,8 @@ access(all) fun transferNFT(id: UInt64, owner: auth(Storage) &Account) {
// should not be accessible in this function
// BAD
access(all) fun transferNFT(id: UInt64, owner: auth(Storage) &Account) {
access(all)
fun transferNFT(id: UInt64, owner: auth(Storage) &Account) {
assert(owner(id) == owner.address)
transfer(id)
Expand Down Expand Up @@ -120,27 +122,39 @@ and then a new creation function can be potentially included within the admin re
// Pseudo-code
// BAD
access(all) contract Currency {
access(all) resource Admin {
access(all) fun mintTokens()
access(all)
contract Currency {
access(all)
resource Admin {
access(all)
fun mintTokens()
}
// Anyone in the network can call this function
// And use the Admin resource to mint tokens
access(all) fun createAdmin(): @Admin {
access(all)
fun createAdmin(): @Admin {
return <-create Admin()
}
}
// This contract makes the admin creation private and in the initializer
// so that only the one who controls the account can mint tokens
// GOOD
access(all) contract Currency {
access(all) resource Admin {
access(all) fun mintTokens()
access(all)
contract Currency {
access(all)
resource Admin {
access(all)
fun mintTokens()
// Only an admin can create new Admins
access(all) fun createAdmin(): @Admin {
access(all)
fun createAdmin(): @Admin {
return <-create Admin()
}
}
Expand Down Expand Up @@ -181,14 +195,18 @@ which increments the number that tracks the play IDs and emits an event:
// Simplified Code
// BAD
//
access(all) contract TopShot {
access(all)
contract TopShot {
// The Record that is used to track every unique play ID
access(all) var nextPlayID: UInt32
access(all)
var nextPlayID: UInt32
access(all) struct Play {
access(all)
struct Play {
access(all) let playID: UInt32
access(all)
let playID: UInt32
init() {
Expand Down Expand Up @@ -216,24 +234,30 @@ that creates the plays.
// Update contract state in admin resource functions
// GOOD
//
access(all) contract TopShot {
access(all)
contract TopShot {
// The Record that is used to track every unique play ID
access(all) var nextPlayID: UInt32
access(all)
var nextPlayID: UInt32
access(all) struct Play {
access(all)
struct Play {
access(all) let playID: UInt32
access(all)
let playID: UInt32
init() {
self.playID = TopShot.nextPlayID
}
}
access(all) resource Admin {
access(all)
resource Admin {
// Protected within the private admin resource
access(all) fun createPlay() {
access(all)
fun createPlay() {
// Create the new Play
var newPlay = Play()
Expand Down
85 changes: 60 additions & 25 deletions versioned_docs/version-1.0/design-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,11 @@ Example Snippet:
```cadence
// BAD Practice: Do not hard code storage paths
access(all) contract NamedFields {
access(all) resource Test {}
access(all)
contract NamedFields {
access(all)
resource Test {}
init() {
// BAD: Hard-coded storage path
Expand All @@ -49,11 +52,15 @@ access(all) contract NamedFields {
// GOOD practice: Instead, use a field
//
access(all) contract NamedFields {
access(all) resource Test {}
access(all)
contract NamedFields {
access(all)
resource Test {}
// GOOD: field storage path
access(all) let TestStoragePath: StoragePath
access(all)
let TestStoragePath: StoragePath
init() {
// assign and access the field here and in transactions
Expand Down Expand Up @@ -88,10 +95,12 @@ Example:

```cadence
// BAD: Field is private, so it cannot be read by the public
access(self) let totalSupply: UFix64
access(self)
let totalSupply: UFix64
// GOOD: Field is public, so it can be read and used by anyone
access(all) let totalSupply: UFix64
access(all)
let totalSupply: UFix64
```

## Script-Accessible report
Expand All @@ -117,25 +126,36 @@ See [Script-Accessible public field/function](#script-accessible-public-fieldfun
### Example

```cadence
access(all) contract AContract {
access(all) let BResourceStoragePath: StoragePath
access(all) let BResourcePublicPath: PublicPath
access(all)
contract AContract {
access(all)
let BResourceStoragePath: StoragePath
access(all)
let BResourcePublicPath: PublicPath
init() {
self.BResourceStoragePath = /storage/BResource
self.BResourcePublicPath = /public/BResource
}
// Resource definition
access(all) resource BResource {
access(all) var c: UInt64
access(all) var d: String
access(all)
resource BResource {
access(all)
var c: UInt64
access(all)
var d: String
// Generate a struct with the same fields
// to return when a script wants to see the fields of the resource
// without having to return the actual resource
access(all) fun generateReport(): BReportStruct {
access(all)
fun generateReport(): BReportStruct {
return BReportStruct(c: self.c, d: self.d)
}
Expand All @@ -146,9 +166,14 @@ access(all) contract AContract {
}
// Define a struct with the same fields as the resource
access(all) struct BReportStruct {
access(all) var c: UInt64
access(all) var d: String
access(all)
struct BReportStruct {
access(all)
var c: UInt64
access(all)
var d: String
init(c: UInt64, d: String) {
self.c = c
Expand All @@ -172,7 +197,8 @@ transaction {
import AContract from 0xAContract
// Return the struct with a script
access(all) fun main(account: Address): AContract.BReportStruct {
access(all)
fun main(account: Address): AContract.BReportStruct {
// borrow the resource
let b = getAccount(account).capabilities
.borrow<&AContract.BResource>(AContract.BResourcePublicPath)
Expand Down Expand Up @@ -225,12 +251,16 @@ All fields, functions, types, variables, etc., need to have names that clearly d
```cadence
// BAD: Unclear naming
//
access(all) contract Tax {
access(all)
contract Tax {
// Do not use abbreviations unless absolutely necessary
access(all) var pcnt: UFix64
access(all)
var pcnt: UFix64
// Not clear what the function is calculating or what the parameter should be
access(all) fun calculate(num: UFix64): UFix64 {
access(all)
fun calculate(num: UFix64): UFix64 {
// What total is this referring to?
let total = num + (num * self.pcnt)
Expand All @@ -240,13 +270,17 @@ access(all) contract Tax {
// GOOD: Clear naming
//
access(all) contract TaxUtilities {
access(all)
contract TaxUtilities {
// Clearly states what the field is for
access(all) var taxPercentage: UFix64
access(all)
var taxPercentage: UFix64
// Clearly states that this function calculates the
// total cost after tax
access(all) fun calculateTotalCostPlusTax(preTaxCost: UFix64): UFix64 {
access(all)
fun calculateTotalCostPlusTax(preTaxCost: UFix64): UFix64 {
let postTaxCost = preTaxCost + (preTaxCost * self.taxPercentage)
return postTaxCost
Expand Down Expand Up @@ -281,7 +315,8 @@ This could be used when purchasing an NFT to verify that the NFT was deposited i
transaction {
access(all) let buyerCollectionRef: &NonFungibleToken.Collection
access(all)
let buyerCollectionRef: &NonFungibleToken.Collection
prepare(acct: auth(BorrowValue) &Account) {
Expand Down
35 changes: 24 additions & 11 deletions versioned_docs/version-1.0/language/access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ Fields can only be assigned to and mutated from within the same or inner scope.
For example, to make a function publicly accessible (`access(all)` is explained below):

```
access(all) fun test() {}
access(all)
fun test() {}
```

There are five levels of access control:
Expand Down Expand Up @@ -112,54 +113,64 @@ from inside the contract they are declared in.
```cadence
// Declare a private constant, inaccessible/invisible in outer scope.
//
access(self) let a = 1
access(self)
let a = 1
// Declare a public constant, accessible/visible in all scopes.
//
access(all) let b = 2
access(all)
let b = 2
```

```cadence
// Declare a public struct, accessible/visible in all scopes.
//
access(all) struct SomeStruct {
access(all)
struct SomeStruct {
// Declare a private constant field which is only readable
// in the current and inner scopes.
//
access(self) let a: Int
access(self)
let a: Int
// Declare a public constant field which is readable in all scopes.
//
access(all) let b: Int
access(all)
let b: Int
// Declare a private variable field which is only readable
// and writable in the current and inner scopes.
//
access(self) var c: Int
access(self)
var c: Int
// Declare a public variable field which is not settable,
// so it is only writable in the current and inner scopes,
// and readable in all scopes.
//
access(all) var d: Int
access(all)
var d: Int
// Arrays and dictionaries declared without (set) cannot be
// mutated in external scopes
access(all) let arr: [Int]
access(all)
let arr: [Int]
// The initializer is omitted for brevity.
// Declare a private function which is only callable
// in the current and inner scopes.
//
access(self) fun privateTest() {
access(self)
fun privateTest() {
// ...
}
// Declare a public function which is callable in all scopes.
//
access(all) fun publicTest() {
access(all)
fun publicTest() {
// ...
}
Expand Down Expand Up @@ -333,6 +344,7 @@ entitlement OuterEntitlement
entitlement InnerEntitlement
resource InnerResource {
access(all)
fun foo() { ... }
Expand Down Expand Up @@ -420,6 +432,7 @@ entitlement mapping OuterToInnerMap {
}
resource InnerResource {
access(all)
fun foo() { ... }
Expand Down
Loading

0 comments on commit 2d3ae7f

Please sign in to comment.