diff --git a/app/components/account/TokenAccountSection.tsx b/app/components/account/TokenAccountSection.tsx
index 6efe44205..32007e72f 100644
--- a/app/components/account/TokenAccountSection.tsx
+++ b/app/components/account/TokenAccountSection.tsx
@@ -14,6 +14,7 @@ import { getCurrentTokenScaledUiAmountMultiplier } from '@utils/token-info';
import { addressLabel } from '@utils/tx';
import { MintAccountInfo, MultisigAccountInfo, TokenAccount, TokenAccountInfo } from '@validators/accounts/token';
import {
+ ConfidentialMintBurn,
ConfidentialTransferAccount,
ConfidentialTransferFeeAmount,
ConfidentialTransferFeeConfig,
@@ -556,6 +557,7 @@ function cmpExtension(a: TokenExtension, b: TokenExtension) {
'confidentialTransferFeeConfig',
'confidentialTransferFeeAmount',
'confidentialTransferMint',
+ 'confidentialMintBurn',
'interestBearingConfig',
'pausableConfig',
'scaledUiAmountConfig',
@@ -723,6 +725,38 @@ export function TokenExtensionRow(
>
);
}
+ case 'confidentialMintBurn': {
+ const extension = create(tokenExtension.state, ConfidentialMintBurn);
+ return (
+ <>
+ {headerStyle === 'header' ? : null}
+ {extension.confidentialSupply && (
+
+ | Confidential Supply |
+ {extension.confidentialSupply} |
+
+ )}
+ {extension.decryptableSupply && (
+
+ | Decryptable Supply |
+ {extension.decryptableSupply} |
+
+ )}
+ {extension.supplyElgamalPubkey && (
+
+ | Supply Elgamal Pubkey |
+ {extension.supplyElgamalPubkey} |
+
+ )}
+ {extension.pendingBurn && (
+
+ | Pending Burn |
+ {extension.pendingBurn} |
+
+ )}
+ >
+ );
+ }
case 'confidentialTransferFeeConfig': {
const extension = create(tokenExtension.state, ConfidentialTransferFeeConfig);
return (
diff --git a/app/components/account/__tests__/TokenExtensionRow.spec.tsx b/app/components/account/__tests__/TokenExtensionRow.spec.tsx
index 3c2e4c6ef..382a0a0fb 100644
--- a/app/components/account/__tests__/TokenExtensionRow.spec.tsx
+++ b/app/components/account/__tests__/TokenExtensionRow.spec.tsx
@@ -123,6 +123,34 @@ describe('TokenExtensionRow', () => {
expect(screen.getByText('auto')).toBeInTheDocument();
});
+ test('should render confidentialMintBurn extension', async () => {
+ const data = {
+ extension: 'confidentialMintBurn',
+ state: {
+ confidentialSupply: 'confidential-supply',
+ decryptableSupply: 'decryptable-supply',
+ pendingBurn: 'pending-burn',
+ supplyElgamalPubkey: 'test-pubkey',
+ },
+ } as TokenExtension;
+
+ render(
+
+
+
+ {TokenExtensionRow(data, undefined, 6, undefined)}
+
+
+
+ );
+
+ expect(await screen.findByText('Confidential Mint/Burn')).toBeInTheDocument();
+ expect(screen.getByText('Confidential Supply')).toBeInTheDocument();
+ expect(screen.getByText('Decryptable Supply')).toBeInTheDocument();
+ expect(screen.getByText('Supply Elgamal Pubkey')).toBeInTheDocument();
+ expect(screen.getByText('Pending Burn')).toBeInTheDocument();
+ });
+
test('should render confidentialTransferFeeConfig extension', async () => {
const data = {
extension: 'confidentialTransferFeeConfig',
diff --git a/app/features/metadata/mocks.ts b/app/features/metadata/mocks.ts
index b869fb145..82a0e9130 100644
--- a/app/features/metadata/mocks.ts
+++ b/app/features/metadata/mocks.ts
@@ -155,6 +155,15 @@ export function getTokenExtension(): TokenExtension[] {
autoApproveNewAccounts: false,
},
},
+ {
+ extension: 'confidentialMintBurn',
+ state: {
+ confidentialSupply: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==',
+ decryptableSupply: 'Ut1TB1Rk4QgH7Ddc3f62LeddYtQ+jlqpAV9YbgfwBVAGIUk8',
+ pendingBurn: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==',
+ supplyElgamalPubkey: '9o26anpyrZ+xCtVSPWHy3iARnCPovlneimCHKNQLVks=',
+ },
+ },
{
extension: 'confidentialTransferFeeConfig',
state: {
diff --git a/app/utils/token-extension.ts b/app/utils/token-extension.ts
index 2cbd8d1c4..ca219b29e 100644
--- a/app/utils/token-extension.ts
+++ b/app/utils/token-extension.ts
@@ -176,6 +176,17 @@ export function populatePartialParsedTokenExtension(
tooltip: description,
};
}
+ case 'confidentialMintBurn': {
+ const description =
+ 'Allow token issuers to opt in to encrypted mint and burn operations, along with encrypted total supply';
+ return {
+ description,
+ externalLinks: populateExternalLinks('https://spl.solana.com/confidential-token/quickstart'),
+ name: 'Confidential Mint/Burn',
+ status: 'active',
+ tooltip: description,
+ };
+ }
case 'interestBearingConfig': {
const description = 'Allows the token balance to be displayed with accumulated interest';
return {
diff --git a/app/validators/accounts/token-extension.ts b/app/validators/accounts/token-extension.ts
index 1bf60e565..7fd1a7da9 100644
--- a/app/validators/accounts/token-extension.ts
+++ b/app/validators/accounts/token-extension.ts
@@ -8,6 +8,7 @@ const ExtensionType = enums([
'mintCloseAuthority',
'confidentialTransferMint',
'confidentialTransferAccount',
+ 'confidentialMintBurn',
'defaultAccountState',
'immutableOwner',
'memoTransfer',
@@ -92,6 +93,13 @@ export const ConfidentialTransferMint = type({
autoApproveNewAccounts: boolean(),
});
+export const ConfidentialMintBurn = type({
+ confidentialSupply: string(),
+ decryptableSupply: string(),
+ pendingBurn: string(),
+ supplyElgamalPubkey: string(),
+});
+
export const ConfidentialTransferFeeConfig = type({
authority: nullable(PublicKeyFromString),
harvestToMintEnabled: boolean(),
diff --git a/bench/BUILD.md b/bench/BUILD.md
index e19d6c0f8..8e8facef2 100644
--- a/bench/BUILD.md
+++ b/bench/BUILD.md
@@ -1,32 +1,32 @@
| Type | Route | Size | First Load JS |
|------|-------|------|---------------|
-| Static | `/` | 15.8 kB | 1.01 MB |
-| Static | `/_not-found` | 332 B | 161 kB |
+| Static | `/` | 15.7 kB | 1.01 MB |
+| Static | `/_not-found` | 334 B | 161 kB |
| Dynamic | `/address/[address]` | 11.7 kB | 301 kB |
| Dynamic | `/address/[address]/anchor-account` | 5.76 kB | 992 kB |
-| Dynamic | `/address/[address]/anchor-program` | 332 B | 161 kB |
+| Dynamic | `/address/[address]/anchor-program` | 333 B | 161 kB |
| Dynamic | `/address/[address]/attestation` | 6.67 kB | 972 kB |
| Dynamic | `/address/[address]/attributes` | 2.49 kB | 931 kB |
| Dynamic | `/address/[address]/blockhashes` | 1.88 kB | 926 kB |
-| Dynamic | `/address/[address]/compression` | 5.26 kB | 959 kB |
+| Dynamic | `/address/[address]/compression` | 5.27 kB | 959 kB |
| Dynamic | `/address/[address]/concurrent-merkle-tree` | 3.75 kB | 952 kB |
-| Dynamic | `/address/[address]/domains` | 13.9 kB | 933 kB |
-| Dynamic | `/address/[address]/entries` | 3.08 kB | 939 kB |
+| Dynamic | `/address/[address]/domains` | 13.8 kB | 932 kB |
+| Dynamic | `/address/[address]/entries` | 3.09 kB | 939 kB |
| Dynamic | `/address/[address]/feature-gate` | 333 B | 161 kB |
| Dynamic | `/address/[address]/idl` | 134 kB | 607 kB |
| Dynamic | `/address/[address]/instructions` | 2.12 kB | 1.03 MB |
| Dynamic | `/address/[address]/metadata` | 3.89 kB | 945 kB |
| Dynamic | `/address/[address]/nftoken-collection-nfts` | 5.97 kB | 971 kB |
-| Dynamic | `/address/[address]/program-multisig` | 3.4 kB | 995 kB |
+| Dynamic | `/address/[address]/program-multisig` | 3.4 kB | 994 kB |
| Dynamic | `/address/[address]/rewards` | 3.69 kB | 930 kB |
| Dynamic | `/address/[address]/security` | 10.9 kB | 1.02 MB |
-| Dynamic | `/address/[address]/slot-hashes` | 3.59 kB | 930 kB |
-| Dynamic | `/address/[address]/stake-history` | 3.73 kB | 930 kB |
-| Dynamic | `/address/[address]/token-extensions` | 8.67 kB | 990 kB |
-| Dynamic | `/address/[address]/tokens` | 7.98 kB | 1.12 MB |
+| Dynamic | `/address/[address]/slot-hashes` | 3.6 kB | 930 kB |
+| Dynamic | `/address/[address]/stake-history` | 3.74 kB | 930 kB |
+| Dynamic | `/address/[address]/token-extensions` | 8.67 kB | 991 kB |
+| Dynamic | `/address/[address]/tokens` | 7.97 kB | 1.12 MB |
| Dynamic | `/address/[address]/transfers` | 3.52 kB | 1.06 MB |
| Dynamic | `/address/[address]/verified-build` | 5.94 kB | 997 kB |
-| Dynamic | `/address/[address]/vote-history` | 3.6 kB | 930 kB |
+| Dynamic | `/address/[address]/vote-history` | 3.61 kB | 930 kB |
| Dynamic | `/api/anchor` | 0 B | 0 B |
| Dynamic | `/api/domain-info/[domain]` | 0 B | 0 B |
| Static | `/api/metadata/proxy` | 0 B | 0 B |
@@ -34,16 +34,16 @@
| Dynamic | `/api/programMetadataIdl` | 0 B | 0 B |
| Dynamic | `/api/verified-programs/list/[page]` | 0 B | 0 B |
| Dynamic | `/api/verified-programs/metadata/[programId]` | 0 B | 0 B |
-| Dynamic | `/block/[slot]` | 10.5 kB | 943 kB |
-| Dynamic | `/block/[slot]/accounts` | 4.65 kB | 923 kB |
-| Dynamic | `/block/[slot]/programs` | 5.25 kB | 924 kB |
-| Dynamic | `/block/[slot]/rewards` | 5.17 kB | 929 kB |
-| Dynamic | `/epoch/[epoch]` | 7 kB | 262 kB |
-| Static | `/feature-gates` | 3.54 kB | 928 kB |
+| Dynamic | `/block/[slot]` | 10.4 kB | 943 kB |
+| Dynamic | `/block/[slot]/accounts` | 4.58 kB | 923 kB |
+| Dynamic | `/block/[slot]/programs` | 5.16 kB | 924 kB |
+| Dynamic | `/block/[slot]/rewards` | 5.09 kB | 928 kB |
+| Dynamic | `/epoch/[epoch]` | 6.97 kB | 262 kB |
+| Static | `/feature-gates` | 3.46 kB | 928 kB |
| Static | `/opengraph-image.png` | 0 B | 0 B |
-| Static | `/supply` | 7.08 kB | 930 kB |
+| Static | `/supply` | 7 kB | 930 kB |
| Static | `/tos` | 332 B | 161 kB |
-| Dynamic | `/tx/[signature]` | 34.3 kB | 1.4 MB |
-| Dynamic | `/tx/[signature]/inspect` | 610 B | 1.2 MB |
-| Static | `/tx/inspector` | 623 B | 1.2 MB |
-| Static | `/verified-programs` | 6.13 kB | 169 kB |
\ No newline at end of file
+| Dynamic | `/tx/[signature]` | 34.2 kB | 1.4 MB |
+| Dynamic | `/tx/[signature]/inspect` | 611 B | 1.2 MB |
+| Static | `/tx/inspector` | 624 B | 1.2 MB |
+| Static | `/verified-programs` | 6.1 kB | 169 kB |
\ No newline at end of file