Skip to content

Commit 457e681

Browse files
committed
Merge branch 'master' of github.com:OpenZeppelin/contracts-wizard into stellar-scaffold
2 parents 476c5d3 + aa0f0d2 commit 457e681

46 files changed

Lines changed: 1270 additions & 167 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.changeset/plain-turkeys-film.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@openzeppelin/wizard-stellar': patch
3+
'@openzeppelin/wizard-common': patch
4+
'@openzeppelin/contracts-mcp': patch
5+
---
6+
7+
Stellar: add an explicitImplementations flag that switches from using default_impl macro to explicit definitions

packages/common/src/ai/descriptions/stellar.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export const stellarCommonDescriptions = {
1212
upgradeable: 'Whether the contract can be upgraded.',
1313
access:
1414
'The type of access control to provision. Ownable is a simple mechanism with a single account authorized for all privileged actions. Roles is a flexible mechanism with a separate role for each privileged action. A role can have many authorized accounts.',
15+
explicitImplementations:
16+
'Whether the contract should use explicit trait implementations instead of using the #[default_impl] macro to auto-generate trait method bodies.',
1517
};
1618

1719
export const stellarFungibleDescriptions = {

packages/common/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
export * from './ai/descriptions/common';
21
export * from './ai/descriptions/cairo';
2+
export * from './ai/descriptions/common';
33
export * from './ai/descriptions/solidity';
44
export * from './ai/descriptions/stellar';
55
export * from './ai/descriptions/stylus';
66
export * from './ai/descriptions/uniswap-hooks';
7+
export * from './utils/object';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const pickKeys = <T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K> =>
2+
Object.fromEntries(keys.map(k => [k, obj[k]])) as Pick<T, K>;

packages/core/stellar/src/add-pausable.ts

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { getSelfArg } from './common-options';
22
import type { BaseFunction, ContractBuilder } from './contract';
33
import type { Access } from './set-access-control';
4-
import { requireAccessControl } from './set-access-control';
4+
import { DEFAULT_ACCESS_CONTROL, requireAccessControl } from './set-access-control';
55
import { defineFunctions } from './utils/define-functions';
66

7-
export function addPausable(c: ContractBuilder, access: Access) {
7+
export function addPausable(c: ContractBuilder, access: Access, explicitImplementations: boolean) {
88
c.addUseClause('stellar_contract_utils::pausable', 'self', { alias: 'pausable' });
99
c.addUseClause('stellar_contract_utils::pausable', 'Pausable');
10-
c.addUseClause('stellar_macros', 'default_impl');
10+
if (!explicitImplementations) c.addUseClause('stellar_macros', 'default_impl');
1111

1212
const pausableTrait = {
1313
traitName: 'Pausable',
@@ -16,23 +16,38 @@ export function addPausable(c: ContractBuilder, access: Access) {
1616
section: 'Utils',
1717
};
1818

19-
const pauseFn: BaseFunction = access === 'ownable' ? functions.pause_unused_caller : functions.pause;
20-
const unpauseFn: BaseFunction = access === 'ownable' ? functions.unpause_unused_caller : functions.unpause;
19+
const effectiveAccess = access === false ? DEFAULT_ACCESS_CONTROL : access;
20+
const pauseFn: BaseFunction = effectiveAccess === 'ownable' ? functions.pause_unused_caller : functions.pause;
21+
const unpauseFn: BaseFunction = effectiveAccess === 'ownable' ? functions.unpause_unused_caller : functions.unpause;
2122

2223
c.addTraitFunction(pausableTrait, functions.paused);
2324
c.addTraitFunction(pausableTrait, pauseFn);
2425
c.addTraitFunction(pausableTrait, unpauseFn);
25-
requireAccessControl(c, pausableTrait, pauseFn, access, {
26-
useMacro: true,
27-
role: 'pauser',
28-
caller: 'caller',
29-
});
26+
requireAccessControl(
27+
c,
28+
pausableTrait,
29+
pauseFn,
30+
effectiveAccess,
31+
{
32+
useMacro: true,
33+
role: 'pauser',
34+
caller: 'caller',
35+
},
36+
explicitImplementations,
37+
);
3038

31-
requireAccessControl(c, pausableTrait, unpauseFn, access, {
32-
useMacro: true,
33-
role: 'pauser',
34-
caller: 'caller',
35-
});
39+
requireAccessControl(
40+
c,
41+
pausableTrait,
42+
unpauseFn,
43+
effectiveAccess,
44+
{
45+
useMacro: true,
46+
role: 'pauser',
47+
caller: 'caller',
48+
},
49+
explicitImplementations,
50+
);
3651
}
3752

3853
const functions = defineFunctions({

packages/core/stellar/src/add-upgradeable.ts

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { requireAccessControl } from './set-access-control';
44
import type { BaseFunction, ContractBuilder } from './contract';
55
import { defineFunctions } from './utils/define-functions';
66

7-
export function addUpgradeable(c: ContractBuilder, access: Access) {
7+
export function addUpgradeable(c: ContractBuilder, access: Access, explicitImplementations: boolean) {
88
const functions = defineFunctions({
99
_require_auth: {
1010
args: [getSelfArg(), { name: 'operator', type: '&Address' }],
@@ -34,9 +34,16 @@ export function addUpgradeable(c: ContractBuilder, access: Access) {
3434

3535
c.addTraitFunction(upgradeableTrait, upgradeFn);
3636

37-
requireAccessControl(c, upgradeableTrait, upgradeFn, access, {
38-
useMacro: false,
39-
role: 'upgrader',
40-
caller: 'operator',
41-
});
37+
requireAccessControl(
38+
c,
39+
upgradeableTrait,
40+
upgradeFn,
41+
access,
42+
{
43+
useMacro: false,
44+
role: 'upgrader',
45+
caller: 'operator',
46+
},
47+
explicitImplementations,
48+
);
4249
}

packages/core/stellar/src/common-options.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const defaults: Required<CommonOptions> = {
1010
export const contractDefaults: Required<CommonContractOptions> = {
1111
...defaults,
1212
access: false,
13+
explicitImplementations: false,
1314
} as const;
1415

1516
export interface CommonOptions {
@@ -18,6 +19,7 @@ export interface CommonOptions {
1819

1920
export interface CommonContractOptions extends CommonOptions {
2021
access?: Access;
22+
explicitImplementations?: boolean;
2123
}
2224

2325
export function withCommonDefaults(opts: CommonOptions): Required<CommonOptions> {
@@ -30,6 +32,7 @@ export function withCommonContractDefaults(opts: CommonContractOptions): Require
3032
return {
3133
...withCommonDefaults(opts),
3234
access: opts.access ?? contractDefaults.access,
35+
explicitImplementations: opts.explicitImplementations ?? contractDefaults.explicitImplementations,
3336
};
3437
}
3538

packages/core/stellar/src/contract.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,10 @@ export class ContractBuilder implements Contract {
185185
}
186186
}
187187

188+
addTraitForEachFunctions(baseTrait: BaseTraitImplBlock, functions: Record<string, BaseFunction>) {
189+
Object.values(functions).forEach(fn => this.addTraitFunction(baseTrait, fn));
190+
}
191+
188192
// used for adding a function to a trait implementation block
189193
addTraitFunction(baseTrait: BaseTraitImplBlock, fn: BaseFunction): ContractFunction {
190194
const t = this.addTraitImplBlock(baseTrait);
@@ -241,6 +245,11 @@ export class ContractBuilder implements Contract {
241245
existingFn.tags = [...(existingFn.tags ?? []), tag];
242246
}
243247

248+
setFunctionCode(fn: BaseFunction, code: string[], baseTrait?: BaseTraitImplBlock): void {
249+
const existingFn = this.getOrCreateFunction(fn, baseTrait);
250+
existingFn.code = [...code];
251+
}
252+
244253
addConstructorArgument(arg: Argument): void {
245254
for (const existingArg of this.constructorArgs) {
246255
if (existingArg.name == arg.name) {

packages/core/stellar/src/fungible.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ testFungible('fungible full - complex name', {
9898
upgradeable: true,
9999
});
100100

101+
testFungible('fungible explicit trait implementations', {
102+
explicitImplementations: true,
103+
});
104+
101105
testAPIEquivalence('fungible API default');
102106

103107
testAPIEquivalence('fungible API basic', { name: 'CustomToken', symbol: 'CTK' });

packages/core/stellar/src/fungible.test.ts.md

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,12 +124,12 @@ Generated by [AVA](https://avajs.dev).
124124
}␊
125125
126126
#[only_owner]␊
127-
fn pause(e: &Env, caller: Address) {␊
127+
fn pause(e: &Env, _caller: Address) {␊
128128
pausable::pause(e);␊
129129
}␊
130130
131131
#[only_owner]␊
132-
fn unpause(e: &Env, caller: Address) {␊
132+
fn unpause(e: &Env, _caller: Address) {␊
133133
pausable::unpause(e);␊
134134
}␊
135135
}␊
@@ -208,12 +208,12 @@ Generated by [AVA](https://avajs.dev).
208208
}␊
209209
210210
#[only_owner]␊
211-
fn pause(e: &Env, caller: Address) {␊
211+
fn pause(e: &Env, _caller: Address) {␊
212212
pausable::pause(e);␊
213213
}␊
214214
215215
#[only_owner]␊
216-
fn unpause(e: &Env, caller: Address) {␊
216+
fn unpause(e: &Env, _caller: Address) {␊
217217
pausable::unpause(e);␊
218218
}␊
219219
}␊
@@ -693,3 +693,66 @@ Generated by [AVA](https://avajs.dev).
693693
#[contractimpl]␊
694694
impl Ownable for CustomToken {}␊
695695
`
696+
697+
## fungible explicit trait implementations
698+
699+
> Snapshot 1
700+
701+
`// SPDX-License-Identifier: MIT␊
702+
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.4.1␊
703+
#![no_std]␊
704+
705+
use soroban_sdk::{Address, contract, contractimpl, Env, String};␊
706+
use stellar_tokens::fungible::{Base, FungibleToken};␊
707+
708+
#[contract]␊
709+
pub struct MyToken;␊
710+
711+
#[contractimpl]␊
712+
impl MyToken {␊
713+
pub fn __constructor(e: &Env) {␊
714+
Base::set_metadata(e, 18, String::from_str(e, "MyToken"), String::from_str(e, "MTK"));␊
715+
}␊
716+
}␊
717+
718+
#[contractimpl]␊
719+
impl FungibleToken for MyToken {␊
720+
type ContractType = Base;␊
721+
722+
fn total_supply(e: &Env) -> i128 {␊
723+
Self::ContractType::total_supply(e)␊
724+
}␊
725+
726+
fn balance(e: &Env, account: Address) -> i128 {␊
727+
Self::ContractType::balance(e, &account)␊
728+
}␊
729+
730+
fn allowance(e: &Env, owner: Address, spender: Address) -> i128 {␊
731+
Self::ContractType::allowance(e, &owner, &spender)␊
732+
}␊
733+
734+
fn transfer(e: &Env, from: Address, to: Address, amount: i128) {␊
735+
Self::ContractType::transfer(e, &from, &to, amount);␊
736+
}␊
737+
738+
fn transfer_from(e: &Env, spender: Address, from: Address, to: Address, amount: i128) {␊
739+
Self::ContractType::transfer_from(e, &spender, &from, &to, amount);␊
740+
}␊
741+
742+
fn approve(e: &Env, owner: Address, spender: Address, amount: i128, live_until_ledger: u32) {␊
743+
Self::ContractType::approve(e, &owner, &spender, amount, live_until_ledger);␊
744+
}␊
745+
746+
fn decimals(e: &Env) -> u32 {␊
747+
Self::ContractType::decimals(e)␊
748+
}␊
749+
750+
fn name(e: &Env) -> String {␊
751+
Self::ContractType::name(e)␊
752+
}␊
753+
754+
fn symbol(e: &Env) -> String {␊
755+
Self::ContractType::symbol(e)␊
756+
}␊
757+
}␊
758+
`

0 commit comments

Comments
 (0)