0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Contracts

Last updated at Posted at 2024-10-24

Accountはcontractを保存します。contractは、単なるインターフェースである場合もあります。

Accountは、contractsフィールドを通じてそのInboxを公開します。このフィールドの型はAccount.Contractsです。

Account.Contracts

access(all)
struct Contracts {

    /// The names of all contracts deployed in the account.
    access(all)
    let names: [String]

    /// Returns the deployed contract for the contract/contract interface with the given name in the account, if any.
    ///
    /// Returns nil if no contract/contract interface with the given name exists in the account.
    access(all)
    view fun get(name: String): DeployedContract?

    /// Returns a reference of the given type to the contract with the given name in the account, if any.
    ///
    /// Returns nil if no contract with the given name exists in the account,
    /// or if the contract does not conform to the given type.
    access(all)
    view fun borrow<T: &Any>(name: String): T?

    /// Adds the given contract to the account.
    ///
    /// The `code` parameter is the UTF-8 encoded representation of the source code.
    /// The code must contain exactly one contract or contract interface,
    /// which must have the same name as the `name` parameter.
    ///
    /// All additional arguments that are given are passed further to the initializer
    /// of the contract that is being deployed.
    ///
    /// The function fails if a contract/contract interface with the given name already exists in the account,
    /// if the given code does not declare exactly one contract or contract interface,
    /// or if the given name does not match the name of the contract/contract interface declaration in the code.
    ///
    /// Returns the deployed contract.
    access(Contracts | AddContract)
    fun add(
        name: String,
        code: [UInt8]
    ): DeployedContract

    /// Updates the code for the contract/contract interface in the account.
    ///
    /// The `code` parameter is the UTF-8 encoded representation of the source code.
    /// The code must contain exactly one contract or contract interface,
    /// which must have the same name as the `name` parameter.
    ///
    /// Does **not** run the initializer of the contract/contract interface again.
    /// The contract instance in the world state stays as is.
    ///
    /// Fails if no contract/contract interface with the given name exists in the account,
    /// if the given code does not declare exactly one contract or contract interface,
    /// or if the given name does not match the name of the contract/contract interface declaration in the code.
    ///
    /// Returns the deployed contract for the updated contract.
    access(Contracts | UpdateContract)
    fun update(name: String, code: [UInt8]): DeployedContract

    /// Removes the contract/contract interface from the account which has the given name, if any.
    ///
    /// Returns the removed deployed contract, if any.
    ///
    /// Returns nil if no contract/contract interface with the given name exists in the account.
    access(Contracts | RemoveContract)
    fun remove(name: String): DeployedContract?
}

entitlement Contracts

entitlement AddContract
entitlement UpdateContract
entitlement RemoveContract

Deployed contract

Accountには「デプロイされたコントラクト」、つまりスマートコントラクトのコードが保存されます。

access(all)
struct DeployedContract {
    /// The address of the account where the contract is deployed at.
    access(all)
    let address: Address

    /// The name of the contract.
    access(all)
    let name: String

    /// The code of the contract.
    access(all)
    let code: [UInt8]

    /// Returns an array of `Type` objects representing all the public type declarations in this contract
    /// (e.g. structs, resources, enums).
    ///
    /// For example, given a contract
    /// ```
    /// contract Foo {
    ///
    ///       access(all)
    ///       struct Bar {...}
    ///
    ///       access(all)
    ///       resource Qux {...}
    /// }
    /// ```
    /// then `.publicTypes()` will return an array equivalent to the expression `[Type<Bar>(), Type<Qux>()]`
    access(all)
    view fun publicTypes(): [Type]
}

これは、デプロイされたスマートコントラクトに関する情報のみを提供する型(type)であり、スマートコントラクトのインスタンス、すなわちスマートコントラクトのインポート結果ではないことに注意してください。

Getting a deployed contract

contracts.get関数は、デプロイされたスマートコントラクトを取得します。

access(all)
view fun get(name: String): DeployedContract?

この関数は、指定された名前を持つデプロイされたコントラクトを返します。指定された名前を持つコントラクトがアカウントに存在しない場合、この関数はnilを返します。

例えば、アカウントにTestという名前のスマートコントラクトがデプロイされていると仮定すると、そのスマートコントラクトは以下のようにして取得できます。

let account = getAccount(0x1)
let contract = account.contracts.get(name: "Test")

Borrowing a deployed contract

特定の実行パスに依存したdynamicインポートを効果的に実行するために、コントラクトを「借用」することができます。(補足. オブジェクト移動はコストがあるがリファレンス取得はコストが低くなります。但しこれはLinear Typesが適用されているリソースの場合でありコントラクトの場合も同様にコストを下げられるかは分かりません...)

これは、例えばimport T from 0x1のように静的にコントラクトをインポートする典型的なインポート文とは対照的です。

contracts.borrow関数は、コントラクトインスタンスへの参照を取得します。

access(all)
view fun borrow<T: &Any>(name: String): T?

この関数は、アカウント上にその名前で保存されているスマートコントラクトのインスタンスへの参照を返します。そのコントラクトが存在し、かつ、指定された型Tを持つ場合です。指定された名前のスマートコントラクトがアカウント上に存在しない場合、この関数はnilを返します。

例えば、Testという名前のスマートコントラクトがTestInterfaceインターフェースに準拠してアカウントにデプロイされていると仮定すると、スマートコントラクトインスタンスへの参照は以下のようにして取得できます。

let account = getAccount(0x1)
let contract: &TestInterface = account.contracts.borrow<&TestInterface>(name: "Test")

import文に似ています。

import Test from 0x1

Deploying a new contract

contracts.add関数は、新しいコントラクトをアカウントにデプロイします。

access(Contracts | AddContract)
fun add(
    name: String,
    code: [UInt8],
    ... contractInitializerArguments
): DeployedContract

add関数を呼び出すには、粗粒度のContracts権限(auth(Contracts) &Account)または細粒度のAddContract権限(auth(AddContract) &Account)で認証された参照経由でアカウントにアクセスする必要があります。

codeパラメータは、UTF-8エンコードで表現されたソースコードです。codeにはnameパラメータと正確に同じ名前の、1つのcontractまたはコントラクトインターフェースを含んでいる必要があります

add関数は、呼び出し時のすべての追加引数(contractInitializerArguments)をコントラクトの初期化子(init)に渡します。

指定された名前のスマートコントラクトが(これからデプロイする)アカウントにすでに存在する場合、コードが宣言する(declare)コントラクトまたはコントラクトインターフェースが一つでない場合、またはnameで指定された名前がコード内のcontract宣言の名前と一致しない場合、関数はプログラムを中断します。

デプロイが成功した場合は、その関数はデプロイされたコントラクトを返します。

例えば、以下のコントラクトコードがデプロイされると仮定します。

access(all)
contract Test {

    access(all)
    let message: String

    init(message: String) {
        self.message = message
    }
}

コントラクトは以下のようにしてデプロイすることができます:

transaction(code: String) {
    prepare(signer: auth(AddContract) &Account) {
        signer.contracts.add(
            name: "Test",
            code: code.utf8,
            message: "I'm a new contract in an existing account"
        )
    }
}

Updating a deployed contract

contracts.update 関数は、既存のスマートコントラクトのコードを更新します。

access(Contracts | UpdateContract)
fun update(name: String, code: [UInt8]): DeployedContract

update関数を呼び出すには、粗粒度のContracts権限(auth(Contracts) &Account)または細粒度のUpdateContract権限(auth(UpdateContract) &Account)で認証された参照経由でアカウントにアクセスする必要があります。

codeパラメータは、UTF-8でエンコードされたソースコードの表現です。コードには、正確に1つのコントラクトまたはコントラクトインターフェースを含める必要があります。このコントラクトまたはコントラクトインターフェースの名前は、nameパラメータと同じ名前にする必要があります

アカウントに指定された名前のスマートコントラクトが存在しない場合、指定されたコードが正確に1つのコントラクトまたはコントラクトインターフェースを宣言していない場合、または指定された名前がコード内の契約宣言の名前と一致しない場合、この関数はプログラムを中断します。

更新が成功すると、この関数はデプロイされたスマートコントラクトを返します。

⚠ WARNING
update機能は、スマートコントラクトの初期化を再度実行しません
スマートコントラクトを更新しても、コントラクトインスタンスやすでに保存されているデータを変更しません。スマートコントラクトの更新は、コントラクトのコードのみを変更します。
コントラクトの更新は、データの整合性を維持する方法でのみ可能です。特定の制限が適用されます。

例えば、Testという名前のコントラクトがすでにアカウントにデプロイされており、次のコントラクトコードで更新されるべきであると仮定します。

access(all)
contract Test {
    
    access(all)
    let message: String

    init(message: String) {
        self.message = message
    }
}

スマートコントラクトは以下のようにして更新することができます。

transaction(code: String) {
    prepare(signer: auth(UpdateContract) &Account) {
        signer.contracts.update(
            name: "Test",
            code: code
        )
    }
}

Removing a deployed contract

contracts.remove 関数は、デプロイされたスマートコントラクトをアカウントから削除します。

access(Contracts | RemoveContract)
fun remove(name: String): DeployedContract?

remove関数を呼び出すには、粗粒度のContracts権限(auth(Contracts) &Account)または細粒度のRemoveContract権限(auth(RemoveContract) &Account)で認証された参照によるアカウントへのアクセスが必要です。

この関数は、アカウントから指定された名前を持つコントラクトを削除し、それを返します。指定された名前を持つスマートコントラクトがアカウントに存在しない場合、この関数はnilを返します。

例えば、Testという名前のコントラクトがアカウントにデプロイされていると仮定すると、スマートコントラクトは次のように削除できます。

transaction(code: String) {
    prepare(signer: auth(RemoveContract) &Account) {
        signer.contracts.remove(name: "Test",)
    }
}

翻訳元->https://cadence-lang.org/docs/language/accounts/contracts

Flow BlockchainのCadence version1.0ドキュメント (Contracts)

Previous << Keys

Next >> Inbox

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?