@openzeppelin/ui-builder-adapter-stellar 1.4.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,7 @@ import type {
14
14
  EnrichedRoleAssignment,
15
15
  EnrichedRoleMember,
16
16
  ExecutionConfig,
17
+ ExpirationMetadata,
17
18
  HistoryQueryOptions,
18
19
  OperationResult,
19
20
  OwnershipInfo,
@@ -236,6 +237,20 @@ export class StellarAccessControlService implements AccessControlService {
236
237
  `Reading ownership status for ${contractAddress}`
237
238
  );
238
239
 
240
+ // Defense-in-depth: check capabilities before calling get_owner()
241
+ // Only applies when contract is registered (context available for schema-based detection)
242
+ const context = this.contractContexts.get(contractAddress);
243
+ if (context) {
244
+ const capabilities = detectAccessControlCapabilities(context.contractSchema);
245
+ if (!capabilities.hasOwnable) {
246
+ throw new OperationFailed(
247
+ 'Contract does not implement the Ownable interface — no get_owner() function available',
248
+ contractAddress,
249
+ 'getOwnership'
250
+ );
251
+ }
252
+ }
253
+
239
254
  // T020: Call get_owner() for current owner
240
255
  const basicOwnership = await readOwnership(contractAddress, this.networkConfig);
241
256
 
@@ -631,6 +646,31 @@ export class StellarAccessControlService implements AccessControlService {
631
646
  return { id: result.txHash };
632
647
  }
633
648
 
649
+ // ── Expiration Metadata ────────────────────────────────────────────────
650
+
651
+ /**
652
+ * Get expiration metadata for a transfer type.
653
+ *
654
+ * Stellar semantics: Both ownership and admin transfers require a user-provided
655
+ * expiration ledger number.
656
+ *
657
+ * @param contractAddress - Contract address (validated but not used for Stellar)
658
+ * @param _transferType - 'ownership' or 'admin' (same semantics for both on Stellar)
659
+ * @returns Expiration metadata indicating required ledger number input
660
+ */
661
+ async getExpirationMetadata(
662
+ contractAddress: string,
663
+ _transferType: 'ownership' | 'admin'
664
+ ): Promise<ExpirationMetadata> {
665
+ validateContractAddress(contractAddress);
666
+
667
+ return {
668
+ mode: 'required',
669
+ label: 'Expiration Ledger',
670
+ unit: 'ledger number',
671
+ };
672
+ }
673
+
634
674
  /**
635
675
  * Transfers ownership of the contract using two-step transfer
636
676
  *
@@ -830,6 +870,20 @@ export class StellarAccessControlService implements AccessControlService {
830
870
  `Reading admin status for ${contractAddress}`
831
871
  );
832
872
 
873
+ // Defense-in-depth: check capabilities before calling get_admin()
874
+ // Only applies when contract is registered (context available for schema-based detection)
875
+ const context = this.contractContexts.get(contractAddress);
876
+ if (context) {
877
+ const capabilities = detectAccessControlCapabilities(context.contractSchema);
878
+ if (!capabilities.hasTwoStepAdmin) {
879
+ throw new OperationFailed(
880
+ 'Contract does not implement the two-step admin interface — no get_admin() / accept_admin_transfer() functions available',
881
+ contractAddress,
882
+ 'getAdminInfo'
883
+ );
884
+ }
885
+ }
886
+
833
887
  // Call get_admin() for current admin
834
888
  const currentAdmin = await getAdmin(contractAddress, this.networkConfig);
835
889
 
@@ -1220,6 +1274,20 @@ export class StellarAccessControlService implements AccessControlService {
1220
1274
  `Reading admin for ${contractAddress}`
1221
1275
  );
1222
1276
 
1277
+ // Defense-in-depth: check capabilities before calling get_admin()
1278
+ // Only applies when contract is registered (context available for schema-based detection)
1279
+ const context = this.contractContexts.get(contractAddress);
1280
+ if (context) {
1281
+ const capabilities = detectAccessControlCapabilities(context.contractSchema);
1282
+ if (!capabilities.hasTwoStepAdmin) {
1283
+ throw new OperationFailed(
1284
+ 'Contract does not implement the two-step admin interface — no get_admin() function available',
1285
+ contractAddress,
1286
+ 'getAdminAccount'
1287
+ );
1288
+ }
1289
+ }
1290
+
1223
1291
  return getAdmin(contractAddress, this.networkConfig);
1224
1292
  }
1225
1293
 
package/src/config.ts CHANGED
@@ -26,8 +26,8 @@ export const stellarAdapterConfig: AdapterConfig = {
26
26
  // Wallet connection and integration
27
27
  '@creit.tech/stellar-wallets-kit': '^1.9.5',
28
28
 
29
- // OpenZeppelin Relayer integration (optional, for gasless transactions)
30
- '@openzeppelin/relayer-sdk': '1.1.0',
29
+ // OpenZeppelin Relayer integration for gasless transactions
30
+ '@openzeppelin/relayer-sdk': '1.9.0',
31
31
 
32
32
  // React integration for wallet components
33
33
  react: '^19.0.0',
package/src/index.ts CHANGED
@@ -1,18 +1,23 @@
1
- // Re-export the main adapter class
1
+ import type { EcosystemExport, StellarNetworkConfig } from '@openzeppelin/ui-types';
2
+
3
+ import { StellarAdapter } from './adapter';
4
+ import { stellarAdapterConfig } from './config';
5
+ import { ecosystemMetadata } from './metadata';
6
+ import { stellarNetworks } from './networks';
7
+
8
+ export { ecosystemMetadata } from './metadata';
2
9
  export { StellarAdapter } from './adapter';
3
10
 
4
- // Re-export adapter-specific types
11
+ export const ecosystemDefinition: EcosystemExport = {
12
+ ...ecosystemMetadata,
13
+ networks: stellarNetworks,
14
+ createAdapter: (config) => new StellarAdapter(config as StellarNetworkConfig),
15
+ adapterConfig: stellarAdapterConfig,
16
+ };
17
+
18
+ // Adapter-specific types
5
19
  export type { StellarContractArtifacts } from './types/artifacts';
6
20
  export { isStellarContractArtifacts } from './types/artifacts';
7
21
 
8
- export {
9
- stellarNetworks,
10
- stellarMainnetNetworks,
11
- stellarTestnetNetworks,
12
- // Individual networks
13
- stellarPublic,
14
- stellarTestnet,
15
- } from './networks';
16
-
17
- // Export adapter configuration
18
- export { stellarAdapterConfig } from './config';
22
+ // Individual network exports
23
+ export { stellarPublic, stellarTestnet } from './networks';
@@ -0,0 +1,16 @@
1
+ import { NetworkStellar } from '@web3icons/react';
2
+
3
+ import type { EcosystemMetadata } from '@openzeppelin/ui-types';
4
+
5
+ export const ecosystemMetadata: EcosystemMetadata = {
6
+ id: 'stellar',
7
+ name: 'Stellar',
8
+ description:
9
+ 'Stellar is a fast, energy-efficient blockchain network designed for real-world financial applications. It enables near-instant global payments at low cost, connects digital assets to traditional finance, and supports smart contracts through Soroban.',
10
+ explorerGuidance: 'contract IDs on Stellar Expert',
11
+ addressExample: 'GCKFBEIYV2U22IO2BJ4KVJOIP7XPWQGQFKKWXR6DOSJBV7STMAQSMTGG',
12
+ iconComponent: NetworkStellar,
13
+ bgColorClass: 'bg-sky-100',
14
+ textColorClass: 'text-sky-900',
15
+ defaultFeatureConfig: { enabled: true, showInUI: true },
16
+ };
@@ -16,5 +16,5 @@ export const stellarPublic: StellarNetworkConfig = {
16
16
  networkPassphrase: 'Public Global Stellar Network ; September 2015',
17
17
  explorerUrl: 'https://stellar.expert/explorer/public',
18
18
  iconComponent: NetworkStellar,
19
- indexerUri: 'https://openzeppelin-stellar-mainnet.graphql.subquery.network/',
19
+ accessControlIndexerUrl: 'https://openzeppelin-stellar-mainnet.graphql.subquery.network/',
20
20
  };
@@ -16,5 +16,5 @@ export const stellarTestnet: StellarNetworkConfig = {
16
16
  networkPassphrase: 'Test SDF Network ; September 2015',
17
17
  explorerUrl: 'https://stellar.expert/explorer/testnet',
18
18
  iconComponent: NetworkStellar,
19
- indexerUri: 'https://openzepplin-stellar-testnet.graphql.subquery.network',
19
+ accessControlIndexerUrl: 'https://openzepplin-stellar-testnet.graphql.subquery.network',
20
20
  };