Skip to content

Commit c8a2962

Browse files
authored
Stellar vault (#821)
1 parent d2f0ce3 commit c8a2962

29 files changed

Lines changed: 2104 additions & 5 deletions

File tree

.changeset/stellar-vault.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@openzeppelin/wizard-stellar': patch
3+
'@openzeppelin/wizard-common': patch
4+
'@openzeppelin/contracts-mcp': patch
5+
'@openzeppelin/contracts-cli': patch
6+
---
7+
8+
Add Stellar tokenized `Vault` contract type, a Fungible Token that issues shares for an underlying asset (ERC-4626-style), with support for pausable, upgradeable, and access control options.

packages/cli/src/cli.test.ts.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Generated by [AVA](https://avajs.dev).
1111
`Usage: npx @openzeppelin/contracts-cli <command> [options]␊
1212
1313
Commands:␊
14-
solidity-erc20, solidity-erc721, solidity-erc1155, solidity-stablecoin, solidity-rwa, solidity-account, solidity-governor, solidity-custom, cairo-erc20, cairo-erc721, cairo-erc1155, cairo-account, cairo-multisig, cairo-governor, cairo-vesting, cairo-custom, stellar-fungible, stellar-governor, stellar-stablecoin, stellar-non-fungible, stylus-erc20, stylus-erc721, stylus-erc1155, confidential-erc7984, uniswap-hooks␊
14+
solidity-erc20, solidity-erc721, solidity-erc1155, solidity-stablecoin, solidity-rwa, solidity-account, solidity-governor, solidity-custom, cairo-erc20, cairo-erc721, cairo-erc1155, cairo-account, cairo-multisig, cairo-governor, cairo-vesting, cairo-custom, stellar-fungible, stellar-governor, stellar-stablecoin, stellar-non-fungible, stellar-vault, stylus-erc20, stylus-erc721, stylus-erc1155, confidential-erc7984, uniswap-hooks␊
1515
1616
Generated contract source code is printed to stdout.␊
1717
@@ -25,7 +25,7 @@ Generated by [AVA](https://avajs.dev).
2525
`Usage: npx @openzeppelin/contracts-cli <command> [options]␊
2626
2727
Commands:␊
28-
solidity-erc20, solidity-erc721, solidity-erc1155, solidity-stablecoin, solidity-rwa, solidity-account, solidity-governor, solidity-custom, cairo-erc20, cairo-erc721, cairo-erc1155, cairo-account, cairo-multisig, cairo-governor, cairo-vesting, cairo-custom, stellar-fungible, stellar-governor, stellar-stablecoin, stellar-non-fungible, stylus-erc20, stylus-erc721, stylus-erc1155, confidential-erc7984, uniswap-hooks␊
28+
solidity-erc20, solidity-erc721, solidity-erc1155, solidity-stablecoin, solidity-rwa, solidity-account, solidity-governor, solidity-custom, cairo-erc20, cairo-erc721, cairo-erc1155, cairo-account, cairo-multisig, cairo-governor, cairo-vesting, cairo-custom, stellar-fungible, stellar-governor, stellar-stablecoin, stellar-non-fungible, stellar-vault, stylus-erc20, stylus-erc721, stylus-erc1155, confidential-erc7984, uniswap-hooks␊
2929
3030
Generated contract source code is printed to stdout.␊
3131
@@ -539,6 +539,26 @@ Generated by [AVA](https://avajs.dev).
539539
--info.license <string> The license used by the contract, default is "MIT"␊
540540
`
541541

542+
## stellar-vault --help
543+
544+
> Snapshot 1
545+
546+
`stellar-vault: Make a tokenized vault that issues Fungible Token shares for an underlying asset, similar to ERC-4626.␊
547+
548+
Required:␊
549+
--name <string> The name of the contract␊
550+
--symbol <string> The short symbol for the token␊
551+
552+
Options:␊
553+
--decimalsOffset <string> Virtual decimals offset added to the underlying asset decimals to derive the vault share decimals, used to mitigate inflation (donation) attacks via virtual shares. The default of 0 is already safe: it makes such attacks non-profitable. Higher values make attacks orders of magnitude more costly, at the cost of virtual shares absorbing a tiny portion of the value accrued to the vault. Must be between 0 and 10.␊
554+
--pausable Whether privileged accounts will be able to pause specifically marked functionality. Useful for emergency response.␊
555+
--access <ownable|roles> 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.␊
556+
--explicitImplementations Whether the contract should use explicit trait implementations instead of using the default ones provided by the library.␊
557+
--upgradeable Whether the contract can be upgraded.␊
558+
--info.securityContact <string> Email where people can contact you to report security issues. Will only be visible if contract source code is verified.␊
559+
--info.license <string> The license used by the contract, default is "MIT"␊
560+
`
561+
542562
## stylus-erc20 --help
543563

544564
> Snapshot 1

packages/cli/src/cli.test.ts.snap

315 Bytes
Binary file not shown.

packages/cli/src/registry.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@ import {
4141
governor as stellarGovernor,
4242
stablecoin as stellarStablecoin,
4343
nonFungible,
44+
vault as stellarVault,
4445
} from '@openzeppelin/wizard-stellar';
4546
import { stellarPrompts } from '@openzeppelin/wizard-common';
4647
import {
4748
stellarFungibleSchema,
4849
stellarGovernorSchema,
4950
stellarStablecoinSchema,
5051
stellarNonFungibleSchema,
52+
stellarVaultSchema,
5153
} from '@openzeppelin/wizard-common/schemas';
5254

5355
import { erc20 as stylusErc20, erc721 as stylusErc721, erc1155 as stylusErc1155 } from '@openzeppelin/wizard-stylus';
@@ -133,6 +135,7 @@ export const registry = {
133135
opts => nonFungible.print(opts),
134136
stellarPrompts.NonFungible,
135137
),
138+
'stellar-vault': createRegistryEntry(stellarVaultSchema, opts => stellarVault.print(opts), stellarPrompts.Vault),
136139

137140
// Stylus
138141
'stylus-erc20': createRegistryEntry(stylusERC20Schema, opts => stylusErc20.print(opts), stylusPrompts.ERC20),

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const stellarPrompts = {
77
NonFungible:
88
'Make a non-fungible token per the Non-Fungible Token Standard, compatible with SEP-50, similar to ERC-721.',
99
Stablecoin: 'Make a stablecoin that uses Fungible Token Standard, compatible with SEP-41.',
10+
Vault: 'Make a tokenized vault that issues Fungible Token shares for an underlying asset, similar to ERC-4626.',
1011
};
1112

1213
export const stellarCommonDescriptions = {
@@ -38,6 +39,11 @@ export const stellarStablecoinDescriptions = {
3839
votes: 'Whether to enable vote checkpoints and delegation for governance.',
3940
};
4041

42+
export const stellarVaultDescriptions = {
43+
decimalsOffset:
44+
'Virtual decimals offset added to the underlying asset decimals to derive the vault share decimals, used to mitigate inflation (donation) attacks via virtual shares. The default of 0 is already safe: it makes such attacks non-profitable. Higher values make attacks orders of magnitude more costly, at the cost of virtual shares absorbing a tiny portion of the value accrued to the vault. Must be between 0 and 10.',
45+
};
46+
4147
export const stellarGovernorDescriptions = {
4248
version: 'The semantic version label returned by the governor contract.',
4349
votingDelay: 'Number of ledgers between proposal creation and voting start (17,000 ledgers are approx. 1 day).',

packages/common/src/ai/schemas/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export {
3030
stellarInfoSchema,
3131
stellarStablecoinSchema,
3232
stellarNonFungibleSchema,
33+
stellarVaultSchema,
3334
} from './stellar';
3435

3536
export { stylusCommonSchema, stylusERC20Schema, stylusERC721Schema, stylusERC1155Schema } from './stylus';

packages/common/src/ai/schemas/schemas.test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
stellarGovernorSchema,
3131
stellarStablecoinSchema,
3232
stellarNonFungibleSchema,
33+
stellarVaultSchema,
3334
stylusERC20Schema,
3435
stylusERC721Schema,
3536
stylusERC1155Schema,
@@ -96,6 +97,7 @@ const allSchemas: [string, z.ZodRawShape][] = [
9697
['stellarFungible', stellarFungibleSchema],
9798
['stellarStablecoin', stellarStablecoinSchema],
9899
['stellarNonFungible', stellarNonFungibleSchema],
100+
['stellarVault', stellarVaultSchema],
99101
['stylusERC20', stylusERC20Schema],
100102
['stylusERC721', stylusERC721Schema],
101103
['stylusERC1155', stylusERC1155Schema],
@@ -154,6 +156,7 @@ function _stellarTypeAssertions() {
154156
Governor: z.object(stellarGovernorSchema).parse({}),
155157
Stablecoin: z.object(stellarStablecoinSchema).parse({}),
156158
NonFungible: z.object(stellarNonFungibleSchema).parse({}),
159+
Vault: z.object(stellarVaultSchema).parse({}),
157160
};
158161
}
159162

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
stellarFungibleDescriptions,
88
stellarNonFungibleDescriptions,
99
stellarStablecoinDescriptions,
10+
stellarVaultDescriptions,
1011
} from '../../index';
1112

1213
export const stellarInfoSchema = z
@@ -57,6 +58,14 @@ export const stellarStablecoinSchema = {
5758
.describe(stellarStablecoinDescriptions.limitations),
5859
} as const satisfies z.ZodRawShape;
5960

61+
export const stellarVaultSchema = {
62+
name: z.string().describe(commonDescriptions.name),
63+
symbol: z.string().describe(commonDescriptions.symbol),
64+
decimalsOffset: z.string().optional().describe(stellarVaultDescriptions.decimalsOffset),
65+
pausable: z.boolean().optional().describe(commonDescriptions.pausable),
66+
...stellarCommonSchema,
67+
} as const satisfies z.ZodRawShape;
68+
6069
export const stellarNonFungibleSchema = {
6170
name: z.string().describe(commonDescriptions.name),
6271
symbol: z.string().describe(commonDescriptions.symbol),

packages/core/stellar/src/api.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@ import type { FungibleOptions } from './fungible';
33
import type { GovernorOptions } from './governor';
44
import type { NonFungibleOptions } from './non-fungible';
55
import type { StablecoinOptions } from './stablecoin';
6+
import type { VaultOptions } from './vault';
67
import {
78
printStablecoin,
89
defaults as stablecoinDefaults,
910
isAccessControlRequired as stablecoinIsAccessControlRequired,
1011
} from './stablecoin';
12+
import {
13+
printVault,
14+
defaults as vaultDefaults,
15+
isAccessControlRequired as vaultIsAccessControlRequired,
16+
} from './vault';
1117
import {
1218
printFungible,
1319
defaults as fungibledefaults,
@@ -48,6 +54,7 @@ export type Fungible = WizardContractAPI<FungibleOptions> & AccessControlAPI<Fun
4854
export type Governor = WizardContractAPI<GovernorOptions> & AccessControlAPI<GovernorOptions>;
4955
export type NonFungible = WizardContractAPI<NonFungibleOptions> & AccessControlAPI<NonFungibleOptions>;
5056
export type Stablecoin = WizardContractAPI<StablecoinOptions> & AccessControlAPI<StablecoinOptions>;
57+
export type Vault = WizardContractAPI<VaultOptions> & AccessControlAPI<VaultOptions>;
5158

5259
export const fungible: Fungible = {
5360
print: printFungible,
@@ -72,3 +79,9 @@ export const stablecoin: Stablecoin = {
7279
defaults: stablecoinDefaults,
7380
isAccessControlRequired: stablecoinIsAccessControlRequired,
7481
};
82+
83+
export const vault: Vault = {
84+
print: printVault,
85+
defaults: vaultDefaults,
86+
isAccessControlRequired: vaultIsAccessControlRequired,
87+
};

packages/core/stellar/src/build-generic.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import type { NonFungibleOptions } from './non-fungible';
66
import { buildNonFungible } from './non-fungible';
77
import type { StablecoinOptions } from './stablecoin';
88
import { buildStablecoin } from './stablecoin';
9+
import type { VaultOptions } from './vault';
10+
import { buildVault } from './vault';
911

1012
export interface KindedOptions {
1113
Fungible: { kind: 'Fungible' } & FungibleOptions;
1214
Governor: { kind: 'Governor' } & GovernorOptions;
1315
NonFungible: { kind: 'NonFungible' } & NonFungibleOptions;
1416
Stablecoin: { kind: 'Stablecoin' } & StablecoinOptions;
17+
Vault: { kind: 'Vault' } & VaultOptions;
1518
}
1619

1720
export type GenericOptions = KindedOptions[keyof KindedOptions];
@@ -30,6 +33,9 @@ export function buildGeneric(opts: GenericOptions) {
3033
case 'Stablecoin':
3134
return buildStablecoin(opts);
3235

36+
case 'Vault':
37+
return buildVault(opts);
38+
3339
default: {
3440
const _: never = opts;
3541
throw new Error('Unknown kind');

0 commit comments

Comments
 (0)