Previous << Keys
Next >> Inbox
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",)
}
}
翻訳元
Flow BlockchainのCadence version1.0ドキュメント (Contracts)