Closed12

Cadence触りながら学ぶ雑メモ

ぱんだぱんだ

コントラクトにpublicで設定したフィールドは誰でも参照できる

User.cdc
pub contract User {
  pub let name: String // publicに公開
getName.cdc
import "User"
pub fun main(): String {
  let name = User.name
  log("user name is ".concat(name))
}
ぱんだぱんだ

当然publicに公開した関数もだれでも呼び出せる

  pub fun getName(): String {
    return self.name
  }
ぱんだぱんだ

privateなフィールドをコントラクトに定義してユーザー本人しか参照できないようにする。

pub contract User {
  pub let name: String // publicに公開
  access(self) let age: UInt8 // 年齢は公開したくない

普通にprivateで宣言してもできなそう?なのでCapabilityの使用を検討。

ぱんだぱんだ
User.cdc
pub contract User {
  pub let userPublicPath: PublicPath
  pub let userPrivatePath: PrivatePath
  pub let userStoragePath: StoragePath

  init() {
    self.userPublicPath = /public/userResource
    self.userPrivatePath = /private/userResource
    self.userStoragePath = /storage/userResource

    self.account.save(<- create UserResource(name: "user", age: 32), to: self.userStoragePath)
    self.account.link<&UserResource>(self.userPrivatePath, target: self.userStoragePath)
  }

  pub resource UserResource {
    pub let name: String
    pub let age: UInt8

    init(name: String, age: UInt8) {
      self.name = name
      self.age = age
    }
  }
}
ぱんだぱんだ

コントラクトのフィールドではなくてリソースを初期化時にコントラクトアドレスのストレージに保存しておく。ストレージのリソースをloadするのは処理的に大袈裟なので参照をprivateパスに保存しておく。

privateパスなのでアカウント本人しか参照できない。下記のようにスクリプトでコントラクトアドレスのAutuAddressを取得すれば、privateパスの参照を取り出して値を読める。

getAge.cdc
import "User"
pub fun main(): UInt8 {
  let acc = getAuthAccount(0x120e725050340cab)
  let user = acc.getCapability<&User.UserResource>(User.userPrivatePath)
    .borrow() ?? panic("")
  log(user.age)
  return user.age
}
ぱんだぱんだ

コントラクトのストレージに記録するよりもリソースにUser情報をもたせアカウントのストレージに格納するようにしてみる。コントラクトにIDフィールドを追加してユーザーが作成されるごとにインクリメントされるようにする。リソースのフィールドの参照にはinterfaceを作成して制限をかけれるようにする。

pub contract UserCreator {
  pub let userPublicPath: PublicPath
  pub let userPrivatePath: PrivatePath
  pub let userStoragePath: StoragePath

  pub var id: UInt64

  init() {
    self.userPublicPath = /public/user
    self.userPrivatePath = /private/user
    self.userStoragePath = /storage/user
    self.id = 1
  }

  pub resource interface GetName {
    pub fun getName(): String
  }

  pub resource interface GetAge {
    pub fun getAge(): UInt8
  }

  pub resource User: GetName, GetAge {
    pub let name: String
    pub let age: UInt8

    init(name: String, age: UInt8) {
      self.name = name
      self.age = age
    }

    pub fun getName(): String {
      return self.name
    }

    pub fun getAge(): UInt8 {
      return self.age
    }
  }

  pub fun createNewUser(name: String, age: UInt8): @User {
    self.id = self.id + 1
    return <- create User(name: name, age: age)
  }
}
 
 
ぱんだぱんだ

ストレージの保存するのでgetAuthAccount()で認証アカウントを取得して、リソースを保存する。interfaceで制限をかけた参照を作成。

import "UserCreator"
pub fun main(): UInt8 {
  // 新規でユーザーを作成してストレージに保存する
  let acc = getAuthAccount(0xf3fcd2c1a78f5eee)
  let user <- UserCreator.createNewUser(name: "user", age: 32)
  acc.save(<-user, to: UserCreator.userStoragePath)

  // 参照を作成
  let onlyNamePath = /public/userName
  // 名前だけ参照できる参照
  acc.link<&UserCreator.User{UserCreator.GetName}>(onlyNamePath, target: UserCreator.userStoragePath)
  // 年齢も参照できる参照
  acc.link<&UserCreator.User{UserCreator.GetName, UserCreator.GetAge}>(UserCreator.userPublicPath, target: UserCreator.userStoragePath)

  // 参照を取得
  let userRef = acc.getCapability<&UserCreator.User{UserCreator.GetName, UserCreator.GetAge}>(UserCreator.userPublicPath)
    .borrow() ?? panic("can not borrow User reference!")
  let userNameOnlyRef = acc.getCapability<&UserCreator.User{UserCreator.GetName}>(onlyNamePath)
    .borrow() ?? panic("can not borrow User name only reference!")

  log(userRef.getName())
  log(userRef.getAge())
  // フィールド参照はできない
  // userRef.name
  // userRef.age

  log(userNameOnlyRef.getName())
  // userNameOnlyRef.getAge() これは呼べない

  return userRef.getAge()
}
ぱんだぱんだ

linkを作るときはinterfaceで制限を可能な限りかけておくのがよさそう。

ぱんだぱんだ

Pathは/public/path1/path2のように深いパスは書けないよう。これパスが衝突したりしないのだそうか??

ぱんだぱんだ

scriptでgetAuthAccountしてストレージにデータを保存しようとしてもストレージに保存されていない。script内でgetAuthAccountした処理は処理が終わった後に破棄されるっぽい、たしか。

ぱんだぱんだ

link作る時とgetCapabilityするときにinterfaceの制限が一致していないと参照が取れないので結構はまった

このスクラップは2023/04/07にクローズされました