Skip to content

Commit 9238096

Browse files
authored
Merge pull request #240 from onflow/contracts
Edit and consolidate Contracts articles
2 parents d11a23e + c0aef4d commit 9238096

2 files changed

Lines changed: 335 additions & 382 deletions

File tree

docs/language/accounts/contracts.mdx

Lines changed: 5 additions & 325 deletions
Original file line numberDiff line numberDiff line change
@@ -3,331 +3,11 @@ title: Contracts
33
sidebar_position: 5
44
---
55

6-
Accounts store [contracts](../contracts.mdx).
7-
A contract can also just be an [interface](../interfaces.mdx).
6+
Accounts store contracts. A contract can also just be an [interface](../interfaces.mdx).
87

9-
An account exposes its inbox through the `contracts` field,
10-
which has the type `Account.Contracts`.
8+
See [Contracts] for more information.
119

12-
## `Account.Contracts`
10+
<!-- Relative links. Will not render on the page -->
1311

14-
```cadence
15-
access(all)
16-
struct Contracts {
17-
18-
/// The names of all contracts deployed in the account.
19-
access(all)
20-
let names: [String]
21-
22-
/// Returns the deployed contract for the contract/contract interface with the given name in the account, if any.
23-
///
24-
/// Returns nil if no contract/contract interface with the given name exists in the account.
25-
access(all)
26-
view fun get(name: String): DeployedContract?
27-
28-
/// Returns a reference of the given type to the contract with the given name in the account, if any.
29-
///
30-
/// Returns nil if no contract with the given name exists in the account,
31-
/// or if the contract does not conform to the given type.
32-
access(all)
33-
view fun borrow<T: &Any>(name: String): T?
34-
35-
/// Adds the given contract to the account.
36-
///
37-
/// The `code` parameter is the UTF-8 encoded representation of the source code.
38-
/// The code must contain exactly one contract or contract interface,
39-
/// which must have the same name as the `name` parameter.
40-
///
41-
/// All additional arguments that are given are passed further to the initializer
42-
/// of the contract that is being deployed.
43-
///
44-
/// The function fails if a contract/contract interface with the given name already exists in the account,
45-
/// if the given code does not declare exactly one contract or contract interface,
46-
/// or if the given name does not match the name of the contract/contract interface declaration in the code.
47-
///
48-
/// Returns the deployed contract.
49-
access(Contracts | AddContract)
50-
fun add(
51-
name: String,
52-
code: [UInt8]
53-
): DeployedContract
54-
55-
/// Updates the code for the contract/contract interface in the account.
56-
///
57-
/// The `code` parameter is the UTF-8 encoded representation of the source code.
58-
/// The code must contain exactly one contract or contract interface,
59-
/// which must have the same name as the `name` parameter.
60-
///
61-
/// Does **not** run the initializer of the contract/contract interface again.
62-
/// The contract instance in the world state stays as is.
63-
///
64-
/// Fails if no contract/contract interface with the given name exists in the account,
65-
/// if the given code does not declare exactly one contract or contract interface,
66-
/// or if the given name does not match the name of the contract/contract interface declaration in the code.
67-
///
68-
/// Returns the deployed contract for the updated contract.
69-
access(Contracts | UpdateContract)
70-
fun update(name: String, code: [UInt8]): DeployedContract
71-
72-
/// Removes the contract/contract interface from the account which has the given name, if any.
73-
///
74-
/// Returns the removed deployed contract, if any.
75-
///
76-
/// Returns nil if no contract/contract interface with the given name exists in the account.
77-
access(Contracts | RemoveContract)
78-
fun remove(name: String): DeployedContract?
79-
}
80-
81-
entitlement Contracts
82-
83-
entitlement AddContract
84-
entitlement UpdateContract
85-
entitlement RemoveContract
86-
```
87-
88-
## Deployed contract
89-
90-
Accounts store "deployed contracts," that is, the code of the contract:
91-
92-
```cadence
93-
access(all)
94-
struct DeployedContract {
95-
/// The address of the account where the contract is deployed at.
96-
access(all)
97-
let address: Address
98-
99-
/// The name of the contract.
100-
access(all)
101-
let name: String
102-
103-
/// The code of the contract.
104-
access(all)
105-
let code: [UInt8]
106-
107-
/// Returns an array of `Type` objects representing all the public type declarations in this contract
108-
/// (e.g. structs, resources, enums).
109-
///
110-
/// For example, given a contract
111-
/// ```
112-
/// contract Foo {
113-
///
114-
/// access(all)
115-
/// struct Bar {...}
116-
///
117-
/// access(all)
118-
/// resource Qux {...}
119-
/// }
120-
/// ```
121-
/// then `.publicTypes()` will return an array equivalent to the expression `[Type<Bar>(), Type<Qux>()]`
122-
access(all)
123-
view fun publicTypes(): [Type]
124-
}
125-
```
126-
127-
Note that this is type only provides information about a deployed contract,
128-
it is not the contract instance, the result of importing a contract.
129-
130-
## Getting a deployed contract
131-
132-
The function `contracts.get` retrieves a deployed contract:
133-
134-
```cadence
135-
access(all)
136-
view fun get(name: String): DeployedContract?
137-
```
138-
139-
The function returns the [deployed contract](#deployed-contract) with the given name, if any.
140-
If no contract with the given name exists in the account, the function returns `nil`.
141-
142-
For example, assuming that an account has a contract named `Test` deployed to it,
143-
the contract can be retrieved as follows:
144-
145-
```cadence
146-
let account = getAccount(0x1)
147-
let contract = account.contracts.get(name: "Test")
148-
```
149-
150-
## Borrowing a deployed contract
151-
152-
Contracts can be "borrowed" to effectively perform a dynamic import dependent on a specific execution path.
153-
154-
This is in contrast to a typical import statement, for example `import T from 0x1`,
155-
which statically imports a contract.
156-
157-
The `contracts.borrow` function obtains a reference to a contract instance:
158-
159-
```cadence
160-
access(all)
161-
view fun borrow<T: &Any>(name: String): T?
162-
```
163-
164-
The functions returns a reference to the contract instance stored with that name on the account,
165-
if it exists, and if it has the provided type `T`.
166-
If no contract with the given name exists in the account, the function returns `nil`.
167-
168-
For example, assuming that a contract named `Test`
169-
which conforms to the `TestInterface` interface is deployed to an account,
170-
a reference to the contract instance can obtained be as follows:
171-
172-
```cadence
173-
let account = getAccount(0x1)
174-
let contract: &TestInterface = account.contracts.borrow<&TestInterface>(name: "Test")
175-
```
176-
177-
This is similar to the import statement
178-
179-
```cadence
180-
import Test from 0x1
181-
```
182-
183-
## Deploying a new contract
184-
185-
The `contracts.add` function deploys a new contract to an account:
186-
187-
```cadence
188-
access(Contracts | AddContract)
189-
fun add(
190-
name: String,
191-
code: [UInt8],
192-
... contractInitializerArguments
193-
): DeployedContract
194-
```
195-
196-
Calling the `add` function requires access to an account via a reference which is authorized
197-
with the coarse-grained `Contracts` entitlement (`auth(Contracts) &Account`),
198-
or the fine-grained `AddContract` entitlement (`auth(AddContract) &Account`).
199-
200-
The `code` parameter is the UTF-8 encoded representation of the source code.
201-
The code must contain exactly one contract or contract interface,
202-
which must have the same name as the `name` parameter.
203-
204-
The `add` function passes all extra arguments of the call (`contractInitializerArguments`)
205-
to the initializer of the contract.
206-
207-
If a contract with the given name already exists in the account,
208-
if the given code does not declare exactly one contract or contract interface,
209-
or if the given name does not match the name of the contract declaration in the code,
210-
then the function aborts the program.
211-
212-
When the deployment succeeded, the function returns the [deployed contract](#deployed-contract).
213-
214-
For example, assuming the following contract code should be deployed:
215-
216-
```cadence
217-
access(all)
218-
contract Test {
219-
220-
access(all)
221-
let message: String
222-
223-
init(message: String) {
224-
self.message = message
225-
}
226-
}
227-
```
228-
229-
The contract can be deployed as follows:
230-
231-
```cadence
232-
transaction(code: String) {
233-
prepare(signer: auth(AddContract) &Account) {
234-
signer.contracts.add(
235-
name: "Test",
236-
code: code.utf8,
237-
message: "I'm a new contract in an existing account"
238-
)
239-
}
240-
}
241-
```
242-
243-
## Updating a deployed contract
244-
245-
The `contracts.update` function updates the code of an existing contract:
246-
247-
```cadence
248-
access(Contracts | UpdateContract)
249-
fun update(name: String, code: [UInt8]): DeployedContract
250-
```
251-
252-
Calling the `update` function requires access to an account via a reference which is authorized
253-
with the coarse-grained `Contracts` entitlement (`auth(Contracts) &Account`),
254-
or the fine-grained `UpdateContract` entitlement (`auth(UpdateContract) &Account`).
255-
256-
The `code` parameter is the UTF-8 encoded representation of the source code.
257-
The code must contain exactly one contract or contract interface,
258-
which must have the same name as the `name` parameter.
259-
260-
If no contract with the given name exists in the account,
261-
if the given code does not declare exactly one contract or contract interface,
262-
or if the given name does not match the name of the contract declaration in the code,
263-
then the function aborts the program.
264-
265-
When the update succeeded, the function returns the [deployed contract](#deployed-contract).
266-
267-
:::warning
268-
269-
The `update` function does **not** run the initializer of the contract again.
270-
271-
Updating a contract does **not** change the contract instance and its existing stored data.
272-
A contract update only changes the code a contract.
273-
274-
Is only possible to update contracts in ways that keep data consistency.
275-
[Certain restrictions apply](../contract-updatability.md).
276-
277-
:::
278-
279-
For example, assuming that a contract named `Test` is already deployed to the account,
280-
and it should be updated with the following contract code:
281-
282-
```cadence
283-
access(all)
284-
contract Test {
285-
286-
access(all)
287-
let message: String
288-
289-
init(message: String) {
290-
self.message = message
291-
}
292-
}
293-
```
294-
295-
The contract can be updated as follows:
296-
297-
```cadence
298-
transaction(code: String) {
299-
prepare(signer: auth(UpdateContract) &Account) {
300-
signer.contracts.update(
301-
name: "Test",
302-
code: code
303-
)
304-
}
305-
}
306-
```
307-
308-
## Removing a deployed contract
309-
310-
The `contracts.remove` function removes a deployed contract from an account:
311-
312-
```cadence
313-
access(Contracts | RemoveContract)
314-
fun remove(name: String): DeployedContract?
315-
```
316-
317-
Calling the `remove` function requires access to an account via a reference which is authorized
318-
with the coarse-grained `Contracts` entitlement (`auth(Contracts) &Account`),
319-
or the fine-grained `RemoveContract` entitlement (`auth(RemoveContract) &Account`).
320-
321-
The function removes the contract from the account which has the given name and returns it.
322-
If no contract with the given name exists in the account, the function returns `nil`.
323-
324-
For example, assuming that a contract named `Test` is deployed to an account,
325-
the contract can be removed as follows:
326-
327-
```cadence
328-
transaction(code: String) {
329-
prepare(signer: auth(RemoveContract) &Account) {
330-
signer.contracts.remove(name: "Test",)
331-
}
332-
}
333-
```
12+
[Contracts]: ../contracts.mdx
13+
[interface]: ../interfaces.mdx

0 commit comments

Comments
 (0)