Skip to content

Commit 027979c

Browse files
committed
documentation for impl Contract
1 parent 6028b89 commit 027979c

File tree

4 files changed

+83
-2
lines changed

4 files changed

+83
-2
lines changed

docs/book/src/sway-program-types/smart_contracts.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@
55
A smart contract is no different than a script or predicate in that it is a piece of bytecode that is deployed to the blockchain via a [transaction](https://fuellabs.github.io/fuel-specs/master/protocol/tx_format). The main features of a smart contract that differentiate it from scripts or predicates are that it is _callable_ and _stateful_. Put another way, a smart contract is analogous to a deployed API with some database state.
66
<!-- contract:example:end -->
77

8-
The interface of a smart contract, also just called a contract, must be defined strictly with an [ABI declaration](#the-abi-declaration). See [this contract](../examples/wallet_smart_contract.md) for an example.
8+
The interface of a smart contract, also just called a contract, can be explicitly defined with an [ABI declaration](#the-abi-declaration) or implicitly with an [impl Self](#impl-self-contracts) item for the special type "Contract". See [this contract](../examples/wallet_smart_contract.md) for an example on using ABIs.
99

1010
## Syntax of a Smart Contract
1111

12-
As with any Sway program, the program starts with a declaration of what [program type](./index.md) it is. A contract must also either define or import an [ABI declaration](#the-abi-declaration) and implement it.
12+
As with any Sway program, the program starts with a declaration of what [program type](./index.md) it is. When using ABIs, a contract must either define or import an [ABI declaration](#the-abi-declaration) and implement it.
1313

1414
<!-- This section should explain best practices for ABIs -->
1515
<!-- ABI:example:start -->
@@ -100,3 +100,18 @@ Each special parameter is optional and assumes a default value when skipped:
100100
1. The default value for `gas` is the context gas (i.e. the content of the special register `$cgas`). Refer to the [FuelVM specifications](https://fuellabs.github.io/fuel-specs/master/vm) for more information about context gas.
101101
2. The default value for `coins` is 0.
102102
3. The default value for `asset_id` is `b256::zero()`.
103+
104+
## Impl Self Contracts
105+
106+
In some cases, it may be more convenient to avoid declaring an ABI and implement the contract directly, as shown in the example below. In this case, the compiler will automatically create an ABI
107+
named as the package containing the `impl Contract` item, and will insert each function inside the ABI.
108+
109+
```sway
110+
{{#include ../../../../examples/wallet_smart_contract_self_impl/src/main.sw:abi_impl}}
111+
```
112+
113+
Without an ABI, there is no way for scripts and other contracts to use `abi(...)` and call this contract, but it can still be tested, as any other contract. The ABI name will be the "upper camel case" version of the package name containing the "impl Contract" item. `CONTRACT_ID` is a compiler special constant that references the contract being implemented in this file.
114+
115+
```sway
116+
{{#include ../../../../examples/wallet_smart_contract_self_impl/src/main.sw:tests}}
117+
```

examples/Forc.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ members = [
4141
"wallet_abi",
4242
"wallet_contract_caller_script",
4343
"wallet_smart_contract",
44+
"wallet_smart_contract_self_impl",
4445
]
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[project]
2+
authors = ["Fuel Labs <[email protected]>"]
3+
entry = "main.sw"
4+
license = "Apache-2.0"
5+
name = "wallet_smart_contract_self_impl"
6+
7+
[dependencies]
8+
std = { path = "../../sway-lib-std" }
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// ANCHOR: full_wallet
2+
contract;
3+
4+
use std::{asset::transfer, call_frames::msg_asset_id, context::msg_amount};
5+
6+
const OWNER_ADDRESS = Address::from(0x8900c5bec4ca97d4febf9ceb4754a60d782abbf3cd815836c1872116f203f861);
7+
8+
storage {
9+
balance: u64 = 0,
10+
}
11+
12+
// ANCHOR: abi_impl
13+
impl Contract {
14+
#[storage(read, write), payable]
15+
fn receive_funds() {
16+
if msg_asset_id() == AssetId::base() {
17+
// If we received the base asset then keep track of the balance.
18+
// Otherwise, we're receiving other native assets and don't care
19+
// about our balance of coins.
20+
storage.balance.write(storage.balance.read() + msg_amount());
21+
}
22+
}
23+
24+
#[storage(read, write)]
25+
fn send_funds(amount_to_send: u64, recipient_address: Address) {
26+
let sender = msg_sender().unwrap();
27+
match sender {
28+
Identity::Address(addr) => assert(addr == OWNER_ADDRESS),
29+
_ => revert(0),
30+
};
31+
32+
let current_balance = storage.balance.read();
33+
assert(current_balance >= amount_to_send);
34+
35+
storage.balance.write(current_balance - amount_to_send);
36+
37+
// Note: `transfer()` is not a call and thus not an
38+
// interaction. Regardless, this code conforms to
39+
// checks-effects-interactions to avoid re-entrancy.
40+
transfer(
41+
Identity::Address(recipient_address),
42+
AssetId::base(),
43+
amount_to_send,
44+
);
45+
}
46+
}
47+
// ANCHOR_END: abi_impl
48+
49+
// ANCHOR: tests
50+
#[test]
51+
fn tests() {
52+
let w = abi(WalletSmartContractSelfImpl, CONTRACT_ID);
53+
w.receive_funds();
54+
}
55+
// ANCHOR_END: tests
56+
57+
// ANCHOR_END: full_wallet

0 commit comments

Comments
 (0)