Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
71f58f5
refactor fungible
brozorec Jun 18, 2025
d68f897
add stablecoin with limitations
brozorec Jun 18, 2025
c2df2d3
Merge branch 'master' into stablecoin
brozorec Jun 19, 2025
07dbee8
add access control
brozorec Jun 19, 2025
05e63e4
non-fungible with default_impl and fixes
brozorec Jun 19, 2025
4074aee
regenerate tests
brozorec Jun 19, 2025
5d4c226
stablecoin tests and fungible roles
brozorec Jun 19, 2025
a309f6c
remove ContractOverride import
brozorec Jun 19, 2025
11e6da9
clean
brozorec Jun 19, 2025
1fd464e
version rc
brozorec Jun 19, 2025
72c00dd
Update packages/core/stellar/src/contract.ts
brozorec Jun 19, 2025
080c791
api version and fix typo
brozorec Jun 19, 2025
f094f05
fix ai configs
brozorec Jun 23, 2025
2730759
changeset
brozorec Jun 23, 2025
c060bef
merge main and fix adjust ai configs
brozorec Jun 23, 2025
15051c4
prettier
brozorec Jun 23, 2025
5576e65
Update .changeset/ninety-readers-kneel.md
brozorec Jun 24, 2025
2219d8b
Use overridable implicit name function
ericglau Jun 24, 2025
c610a33
suggestions
brozorec Jun 25, 2025
5ccf118
update stellar mcp
brozorec Jun 25, 2025
ab239b9
Add changesets for common and mcp
ericglau Jun 25, 2025
8fe6163
Add stellar stablecoin to MCP readme
ericglau Jun 26, 2025
36a1de2
merge master
brozorec Jun 27, 2025
61b419e
resolve snapshot conflicts
brozorec Jun 27, 2025
e02732e
merge master and resolve conflicts
brozorec Jul 2, 2025
3345a83
bump version and switch to only_role
brozorec Jul 2, 2025
0cc229b
remove pausable caller
brozorec Jul 2, 2025
2a8e74a
update changeset version
brozorec Jul 3, 2025
56ecb43
Merge branch 'master' into stablecoin
brozorec Jul 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/ninety-readers-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@openzeppelin/wizard-stellar': minor
---

Add Stablecoin with Limitations and Access Control (ownable and roles).
- **Breaking changes**:
- Use OpenZeppelin Stellar Soroban Contracts v0.3.0
7 changes: 7 additions & 0 deletions .changeset/proud-brooms-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@openzeppelin/wizard-mcp': patch
---

Stellar: Add Stablecoin with Limitations and Access Control (ownable and roles).
- **Potentially breaking changes**:
- Use OpenZeppelin Stellar Soroban Contracts v0.3.0
5 changes: 5 additions & 0 deletions .changeset/soft-points-obey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@openzeppelin/wizard-common': patch
---

Stellar: Add Stablecoin with Limitations and Access Control (ownable and roles).
8 changes: 8 additions & 0 deletions packages/common/src/ai/descriptions/stellar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ export const stellarPrompts = {
Fungible: 'Make a fungible token per the Fungible Token Standard, compatible with SEP-41, similar to ERC-20.',
NonFungible:
'Make a non-fungible token per the Non-Fungible Token Standard, compatible with SEP-50, similar to ERC-721.',
Stablecoin: 'Make a stablecoin that uses Fungible Token Standard, compatible with SEP-41.',
};

export const stellarCommonDescriptions = {
upgradeable: 'Whether the contract can be upgraded.',
access:
'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.',
};

export const stellarFungibleDescriptions = {
Expand All @@ -20,3 +23,8 @@ export const stellarNonFungibleDescriptions = {
consecutive: 'To batch mint NFTs instead of minting them individually (sequential minting is mandatory).',
sequential: 'Whether the IDs of the minted NFTs will be sequential.',
};

export const stellarStablecoinDescriptions = {
limitations: 'Whether to restrict certain users from transferring tokens, either via allowing or blocking them.',
premint: 'The number of tokens to premint for the deployer.',
};
13 changes: 9 additions & 4 deletions packages/core/stellar/src/add-pausable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { defineFunctions } from './utils/define-functions';
export function addPausable(c: ContractBuilder, access: Access) {
c.addUseClause('stellar_pausable', 'self', { alias: 'pausable' });
c.addUseClause('stellar_pausable', 'Pausable');
c.addUseClause('stellar_default_impl_macro', 'default_impl');

const pausableTrait = {
traitName: 'Pausable',
Expand All @@ -19,8 +20,12 @@ export function addPausable(c: ContractBuilder, access: Access) {
c.addTraitFunction(pausableTrait, functions.pause);
c.addTraitFunction(pausableTrait, functions.unpause);

requireAccessControl(c, pausableTrait, functions.pause, access, 'caller');
requireAccessControl(c, pausableTrait, functions.unpause, access, 'caller');
requireAccessControl(c, pausableTrait, functions.pause, access, { useMacro: true, role: 'pauser', caller: 'caller' });
requireAccessControl(c, pausableTrait, functions.unpause, access, {
useMacro: true,
role: 'pauser',
caller: 'caller',
});
}

const functions = defineFunctions({
Expand All @@ -31,10 +36,10 @@ const functions = defineFunctions({
},
pause: {
args: [getSelfArg(), { name: 'caller', type: 'Address' }],
code: ['pausable::pause(e, &caller)'],
code: ['pausable::pause(e)'],
},
unpause: {
args: [getSelfArg(), { name: 'caller', type: 'Address' }],
code: ['pausable::unpause(e, &caller)'],
code: ['pausable::unpause(e)'],
},
});
8 changes: 6 additions & 2 deletions packages/core/stellar/src/add-upgradeable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export function addUpgradeable(c: ContractBuilder, access: Access) {
const functions = defineFunctions({
_require_auth: {
args: [getSelfArg(), { name: 'operator', type: '&Address' }],
code: ['operator.require_auth();'],
code: [],
},
});

Expand All @@ -26,5 +26,9 @@ export function addUpgradeable(c: ContractBuilder, access: Access) {

c.addTraitFunction(upgradeableTrait, functions._require_auth);

requireAccessControl(c, upgradeableTrait, functions._require_auth, access, '*operator');
requireAccessControl(c, upgradeableTrait, functions._require_auth, access, {
useMacro: false,
role: 'upgrader',
caller: 'operator',
});
}
31 changes: 27 additions & 4 deletions packages/core/stellar/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
import type { CommonContractOptions } from './common-options';
import type { FungibleOptions } from './fungible';
import type { NonFungibleOptions } from './non-fungible';
import { printFungible, defaults as fungibledefaults } from './fungible';
import { printNonFungible, defaults as nonFungibledefaults } from './non-fungible';
import type { StablecoinOptions } from './stablecoin';
import {
printStablecoin,
defaults as stablecoinDefaults,
isAccessControlRequired as stablecoinIsAccessControlRequired,
} from './stablecoin';
import {
printFungible,
defaults as fungibledefaults,
isAccessControlRequired as fungibleIsAccessControlRequired,
} from './fungible';
import {
printNonFungible,
defaults as nonFungibledefaults,
isAccessControlRequired as nonFungibleIsAccessControlRequired,
} from './non-fungible';

export interface WizardContractAPI<Options extends CommonContractOptions> {
/**
Expand All @@ -24,15 +38,24 @@ export interface AccessControlAPI<Options extends CommonContractOptions> {
isAccessControlRequired: (opts: Partial<Options>) => boolean;
}

export type Fungible = WizardContractAPI<FungibleOptions>; // TODO add AccessControlAPI<FungibleOptions> when access control is implemented, if useful
export type NonFungible = WizardContractAPI<NonFungibleOptions>;
export type Fungible = WizardContractAPI<FungibleOptions> & AccessControlAPI<FungibleOptions>;
export type NonFungible = WizardContractAPI<NonFungibleOptions> & AccessControlAPI<NonFungibleOptions>;
export type Stablecoin = WizardContractAPI<StablecoinOptions> & AccessControlAPI<StablecoinOptions>;

export const fungible: Fungible = {
print: printFungible,
defaults: fungibledefaults,
isAccessControlRequired: fungibleIsAccessControlRequired,
};

export const nonFungible: NonFungible = {
print: printNonFungible,
defaults: nonFungibledefaults,
isAccessControlRequired: nonFungibleIsAccessControlRequired,
};

export const stablecoin: Stablecoin = {
print: printStablecoin,
defaults: stablecoinDefaults,
isAccessControlRequired: stablecoinIsAccessControlRequired,
};
6 changes: 6 additions & 0 deletions packages/core/stellar/src/build-generic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ import type { FungibleOptions } from './fungible';
import { buildFungible } from './fungible';
import type { NonFungibleOptions } from './non-fungible';
import { buildNonFungible } from './non-fungible';
import type { StablecoinOptions } from './stablecoin';
import { buildStablecoin } from './stablecoin';

export interface KindedOptions {
Fungible: { kind: 'Fungible' } & FungibleOptions;
NonFungible: { kind: 'NonFungible' } & NonFungibleOptions;
Stablecoin: { kind: 'Stablecoin' } & StablecoinOptions;
}

export type GenericOptions = KindedOptions[keyof KindedOptions];
Expand All @@ -18,6 +21,9 @@ export function buildGeneric(opts: GenericOptions) {
case 'NonFungible':
return buildNonFungible(opts);

case 'Stablecoin':
return buildStablecoin(opts);

default: {
const _: never = opts;
throw new Error('Unknown kind');
Expand Down
22 changes: 11 additions & 11 deletions packages/core/stellar/src/contract.test.ts.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
#[contract]␊
Expand All @@ -21,7 +21,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
#[contract]␊
Expand All @@ -40,7 +40,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
#[contract]␊
Expand All @@ -59,7 +59,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
#[contract]␊
Expand All @@ -81,7 +81,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
#[contract]␊
Expand All @@ -103,7 +103,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
use some::library::SomeLibrary;␊
Expand All @@ -117,7 +117,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
use some::library::{Misc, SomeLibrary};␊
Expand All @@ -131,7 +131,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
#![no_std]␊
use another::library::{self as custom1, self as custom2, AnotherLibrary};␊
Expand All @@ -146,7 +146,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
//! Some documentation␊
#![no_std]␊
Expand All @@ -160,7 +160,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
//! # Security␊
//!␊
Expand All @@ -176,7 +176,7 @@ Generated by [AVA](https://avajs.dev).
> Snapshot 1

`// SPDX-License-Identifier: MIT␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.2.0␊
// Compatible with OpenZeppelin Stellar Soroban Contracts ^0.3.0␊
//! Some documentation␊
Expand Down
Binary file modified packages/core/stellar/src/contract.test.ts.snap
Binary file not shown.
11 changes: 9 additions & 2 deletions packages/core/stellar/src/contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ export interface BaseFunction {
}

export interface ContractFunction extends BaseFunction {
tags: string[];
codeBefore?: string[];
tag?: string;
}

export interface Variable {
Expand Down Expand Up @@ -177,6 +177,7 @@ export class ContractBuilder implements Contract {
const contractFn: ContractFunction = {
...fn,
pub: true,
tags: [],
codeBefore: [],
};
this.freeFunctionsMap.set(signature, contractFn);
Expand All @@ -201,6 +202,7 @@ export class ContractBuilder implements Contract {
// Otherwise, add the function
const contractFn: ContractFunction = {
...fn,
tags: [],
codeBefore: [],
};
t.functions.push(contractFn);
Expand Down Expand Up @@ -236,7 +238,7 @@ export class ContractBuilder implements Contract {

addFunctionTag(fn: BaseFunction, tag: string, baseTrait?: BaseTraitImplBlock): void {
const existingFn = this.getOrCreateFunction(fn, baseTrait);
existingFn.tag = tag;
existingFn.tags = [...(existingFn.tags ?? []), tag];
}

addConstructorArgument(arg: Argument): void {
Expand All @@ -249,6 +251,11 @@ export class ContractBuilder implements Contract {
}

addConstructorCode(code: string): void {
for (const existingCode of this.constructorCode) {
if (existingCode === code) {
return;
}
}
this.constructorCode.push(code);
}

Expand Down
14 changes: 13 additions & 1 deletion packages/core/stellar/src/fungible.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,26 @@ testFungible('fungible ownable', {
access: 'ownable',
});

testFungible('fungible full', {
testFungible('fungible roles', {
access: 'roles',
});

testFungible('fungible full - ownable', {
premint: '2000',
access: 'ownable',
burnable: true,
mintable: true,
pausable: true,
});

testFungible('fungible full - roles', {
premint: '2000',
access: 'roles',
burnable: true,
mintable: true,
pausable: true,
});

testFungible('fungible full - complex name', {
name: 'Custom $ Token',
premint: '2000',
Expand Down
Loading
Loading