-
Notifications
You must be signed in to change notification settings - Fork 12
Add extensibility section #86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 14 commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
49f9627
setup docs, start erc20
andrew-fleming d4d0c35
Add PR and issue templates (#43)
andrew-fleming e5c779c
Add security doc (#42)
andrew-fleming d23a483
chore: add code owners (#53)
0xisk a169a2f
Improve compact scripts (#41)
andrew-fleming 37c92f1
Add license (#44)
andrew-fleming 100d61d
Support compact 0.23.0, migrate to vitest (#68)
andrew-fleming 969ac88
Update .nvmrc (#73)
andrew-fleming 2e4c49c
strip down docs to just setup
andrew-fleming b848d3e
fix nav, improve index doc
andrew-fleming 36897a0
add line
andrew-fleming 6d6e24e
add doc scripts in project root
andrew-fleming 6c6f486
add extensibility doc
andrew-fleming 1ff306c
Merge branch 'main' into add-extensibility-section
emnul 9826c75
Update method signature to latest version
emnul File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
* xref:index.adoc[Overview] | ||
* xref:extensibility.adoc[Extensibility] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
# Extensibility | ||
|
||
## The Module/Contract Pattern | ||
|
||
We use the term *modular composition by delegation* to describe the practice of having contracts call into module-defined circuits to implement behavior. Rather than inheriting or overriding functionality, a contract delegates responsibility to the module by explicitly invoking its exported circuits. | ||
|
||
The idea is that there are two types of compact files: modules and contracts. To minimize risk, boilerplate, and avoid naming clashes, we follow these rules: | ||
|
||
### Modules | ||
|
||
Modules expose functionality through three circuit types: | ||
|
||
1. `internal`: private helpers → used to break up logic within the module. | ||
2. `public`: composable building blocks → intended for contracts to use in complex flows (`_mint`, `_burn`). | ||
3. `external`: standalone circuits → safe to expose as-is (`transfer`, `approve`). | ||
|
||
Modules must: | ||
|
||
- Export only `public` and `external` circuits. | ||
- Prefix `public` circuits with `_` (e.g., `FungibleToken._mint`). | ||
- Avoid `_` prefix for `external` circuits (e.g., `FungibleToken.transfer`). | ||
- Avoid defining or calling constructors or `initialize()` directly. | ||
- Optionally define an `initialize()` circuit for internal setup—but execution must be delegated to the contract. | ||
|
||
**Note**: Compact files must contain only one top-level module and all logic must be defined *inside* the module declaration. | ||
|
||
### Contracts | ||
|
||
Contracts compose behavior by explicitly invoking the relevant circuits from imported modules. Therefore, contracts: | ||
|
||
- Can import from modules. | ||
- Should add prefix to imports (`import "FungibleToken" prefix FungibleToken_;`). | ||
- Should re-expose external module circuits through wrapper circuits to control naming and layering. Avoid raw re-exports to prevent name clashes. | ||
- Should implement constructor that calls `initialize` from imported modules. | ||
- Must not call initializers outside of the constructor. | ||
|
||
This pattern balances modularity with local control, avoids tight coupling, and works within Compact’s language constraints. As Compact matures, this pattern will likely evolve as well. | ||
|
||
### Example contract implementing modules | ||
|
||
```ts | ||
/** FungibleTokenMintablePausableOwnableContract */ | ||
pragma language_version >= 0.15.0; | ||
|
||
import CompactStandardLibrary; | ||
|
||
import FungibleToken prefix FungibleToken_; | ||
import Pausable prefix Pausable_; | ||
import Ownable prefix Ownable_; | ||
|
||
constructor( | ||
_name: Maybe<Opaque<"string">>, | ||
_symbol: Maybe<Opaque<"string">>, | ||
_decimals:Uint<8>, | ||
_owner: Either<ZswapCoinPublicKey, ContractAddress> | ||
) { | ||
FungibleToken_initialize(_name, _symbol, _decimals); | ||
Ownable_initialize(_owner); | ||
} | ||
|
||
/** IFungibleTokenMetadata */ | ||
|
||
export circuit name(): Maybe<Opaque<"string">> { | ||
return FungibleToken_name(); | ||
} | ||
|
||
export circuit symbol(): Maybe<Opaque<"string">> { | ||
return FungibleToken_symbol(); | ||
} | ||
|
||
export circuit decimals(): Uint<8> { | ||
return FungibleToken_decimals(); | ||
} | ||
|
||
/** IFungibleToken */ | ||
|
||
export circuit totalSupply(): Uint<128> { | ||
return FungibleToken_totalSupply(); | ||
} | ||
|
||
export circuit balanceOf( | ||
account: Either<ZswapCoinPublicKey, ContractAddress> | ||
): Uint<128> { | ||
return FungibleToken_balanceOf(account); | ||
} | ||
|
||
export circuit allowance( | ||
owner: Either<ZswapCoinPublicKey, ContractAddress>, | ||
spender: Either<ZswapCoinPublicKey, ContractAddress> | ||
): Uint<128> { | ||
return FungibleToken_allowance(owner, spender); | ||
} | ||
|
||
export circuit transfer( | ||
to: Either<ZswapCoinPublicKey, ContractAddress>, | ||
value: Uint<128> | ||
): Boolean { | ||
Pausable_assertNotPaused(); | ||
return FungibleToken_transfer(to, value); | ||
} | ||
|
||
export circuit transferFrom( | ||
from: Either<ZswapCoinPublicKey, ContractAddress>, | ||
to: Either<ZswapCoinPublicKey, ContractAddress>, | ||
value: Uint<128> | ||
): Boolean { | ||
Pausable_assertNotPaused(); | ||
return FungibleToken_transferFrom(from, to, value); | ||
} | ||
|
||
export circuit approve( | ||
spender: Either<ZswapCoinPublicKey, ContractAddress>, | ||
value: Uint<128> | ||
): Boolean { | ||
Pausable_assertNotPaused(); | ||
return FungibleToken_approve(spender, value); | ||
} | ||
|
||
/** IMintable */ | ||
|
||
export circuit mint( | ||
account: Either<ZswapCoinPublicKey, ContractAddress>, | ||
value: Uint<128> | ||
): [] { | ||
Pausable_assertNotPaused(); | ||
Ownable_assertOnlyOwner(); | ||
return FungibleToken__mint(account, value); | ||
} | ||
|
||
/** IPausable */ | ||
|
||
export circuit isPaused(): Boolean { | ||
return Pausable_isPaused(); | ||
} | ||
|
||
export circuit pause(): [] { | ||
Ownable_assertOnlyOwner(); | ||
return Pausable__pause(); | ||
} | ||
|
||
export circuit unpause(): [] { | ||
Ownable_assertOnlyOwner(); | ||
return Pausable__unpause(); | ||
} | ||
|
||
/** IOwnable */ | ||
|
||
export circuit owner(): Either<ZswapCoinPublicKey, ContractAddress> { | ||
return Ownable_owner(); | ||
} | ||
|
||
export circuit transferOwnership( | ||
newOwner: Either<ZswapCoinPublicKey, ContractAddress> | ||
): [] { | ||
return Ownable_transferOwnership(newOwner); | ||
} | ||
|
||
export circuit renounceOwnership(): [] { | ||
return Ownable_renounceOwnership(); | ||
} | ||
``` |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.