Pausable¶
Source: fourier/stdlib/pausable.fou.
Circuit-breaker pattern. An owner can pause and unpause the contract; protected functions check the flag before doing work and revert if paused.
Storage¶
| Slot | Name | Type | Purpose |
|---|---|---|---|
0 | owner | address | Pause controller |
1 | paused | uint | 0 = running, 1 = paused |
Reserves slots 0 and 1. Your contract's storage must start at slot 2 or higher.
Source¶
contract Pausable {
storage owner: address @ 0;
storage paused: uint @ 1;
fn init() {
owner = caller();
paused = 0;
}
pub fn pause() {
require(caller() == owner);
paused = 1;
}
pub fn unpause() {
require(caller() == owner);
paused = 0;
}
pub fn is_paused() -> uint {
return paused;
}
pub fn protected_action() -> uint {
require(paused == 0);
// ... your logic here ...
return 1;
}
}
Selectors¶
| Selector | Function |
|---|---|
0x01 | pause() |
0x02 | unpause() |
0x03 | is_paused() -> uint |
0x04 | protected_action() -> uint |
Usage: inherit-by-copy¶
Copy the storage decls and the pause/unpause functions; gate each mutating function with require(paused == 0):
contract Token {
storage owner: address @ 0; // from Pausable
storage paused: uint @ 1; // from Pausable
storage total_supply: uint @ 2;
storage balances: map[address, uint] @ 3;
fn init() {
owner = caller();
paused = 0;
total_supply = 1_000_000;
balances[caller()] = total_supply;
}
pub fn pause() {
require(caller() == owner);
paused = 1;
}
pub fn unpause() {
require(caller() == owner);
paused = 0;
}
pub fn transfer(to: address, amount: uint) -> bool {
require(paused == 0); // pausable gate
let bal: uint = balances[caller()];
require(bal >= amount);
balances[caller()] = bal - amount;
balances[to] = balances[to] + amount;
return true;
}
}
Pattern: pause read paths too?¶
Whether to gate read-only functions on paused is application-specific. Standard practice is to leave reads open (you usually want users to inspect their balance even when transfers are paused) and only gate mutating paths.
Combining with Ownable¶
Pausable's owner field is the same slot as Ownable's. If you want both transfer_ownership and pause, copy Ownable's functions in alongside Pausable's — they share storage slot 0:
storage owner: address @ 0; // from both Pausable and Ownable
storage paused: uint @ 1; // from Pausable
// ... your storage at slot 2+ ...
pub fn transfer_ownership(new_owner: address) { // Ownable
require(caller() == owner);
owner = new_owner;
}
pub fn pause() { // Pausable
require(caller() == owner);
paused = 1;
}
// ...
Events¶
Pausable as shipped does not emit events. Add them in your copy if you need indexers to track pause state: