Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit cbfe754

Browse files
authored
docs: Add CPI Guard extension info (#5876)
1 parent 7ff12ef commit cbfe754

File tree

1 file changed

+140
-0
lines changed

1 file changed

+140
-0
lines changed

docs/src/token-2022/extensions.mdx

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,146 @@ import {
13081308
</TabItem>
13091309
</Tabs>
13101310

1311+
### CPI Guard
1312+
1313+
CPI Guard is an extension that prohibits certain actions inside cross-program
1314+
invocations, to protect users from implicitly signing for actions they can't see,
1315+
hidden in programs that aren't the System or Token programs.
1316+
1317+
Users may choose to enable or disable the CPI Guard extension on their token
1318+
account at will. When enabled, it has the following effects during CPI:
1319+
1320+
* Transfer: the signing authority must be the account delegate
1321+
* Burn: the signing authority must be the account delegate
1322+
* Approve: prohibited
1323+
* Close Account: the lamport destination must be the account owner
1324+
* Set Close Authority: prohibited unless unsetting
1325+
* Set Owner: always prohibited, including outside CPI
1326+
1327+
#### Background
1328+
1329+
When interacting with a dapp, users sign transactions that are constructed by
1330+
frontend code. Given a user's signature, there are three fundamental ways for a
1331+
dapp to transfer funds from the user to the dapp (or, equivalently, burn them):
1332+
1333+
* Insert a transfer instruction in the transaction
1334+
* Insert an approve instruction in the transaction, and perform a CPI transfer
1335+
under program authority
1336+
* Insert an opaque program instruction, and perform a CPI transfer with the user's
1337+
authorization
1338+
1339+
The first two are safe, in that the user can see exactly what is being done, with
1340+
zero ambiguity. The third is quite dangerous. A wallet signature allows the program
1341+
to perform any action as the user, without any visibility into its actions. There
1342+
have been some attempts at workarounds, for instance, simulating the transaction
1343+
and warning about balance changes. But, fundamentally, this is intractable.
1344+
1345+
There are two ways to make this much safer:
1346+
1347+
* Wallets warn whenever a wallet signature is made available to an opaque
1348+
(non-system, non-token) instruction. Users should be educated to treat the request
1349+
for a signature on such an instruction as highly suspect
1350+
* The token program prohibits CPI calls with the user authority, forcing opaque
1351+
programs to directly ask for the user's authority
1352+
1353+
The CPI Guard covers the second instance.
1354+
1355+
#### Example: Enable CPI Guard on a token account
1356+
1357+
<Tabs className="unique-tabs" groupId="language-selection">
1358+
<TabItem value="cli" label="CLI" default>
1359+
```console
1360+
$ spl-token enable-cpi-guard 4YfkXX89TrsWqSSxb3av36Rk8EZBoDqxGzuaDNXr7UnL
1361+
1362+
Signature: 2fohon7oraTCgBZB3dfzhpGsBobYmYPgA8nvgCqKzjqpdX6EYZaBY3VwzjNuwDpsFYYNbpTVYBjxqiaMBrvXM8S2
1363+
```
1364+
</TabItem>
1365+
<TabItem value="jsx" label="JS">
1366+
```jsx
1367+
import {
1368+
clusterApiUrl,
1369+
sendAndConfirmTransaction,
1370+
Connection,
1371+
Keypair,
1372+
SystemProgram,
1373+
Transaction,
1374+
LAMPORTS_PER_SOL,
1375+
} from '@solana/web3.js';
1376+
import {
1377+
createMint,
1378+
createEnableCpiGuardInstruction,
1379+
createInitializeAccountInstruction,
1380+
disableCpiGuard,
1381+
enableCpiGuard,
1382+
getAccountLen,
1383+
ExtensionType,
1384+
TOKEN_2022_PROGRAM_ID,
1385+
} from '../src';
1386+
1387+
(async () => {
1388+
const connection = new Connection(clusterApiUrl('devnet'), 'confirmed');
1389+
1390+
const payer = Keypair.generate();
1391+
const airdropSignature = await connection.requestAirdrop(payer.publicKey, 2 * LAMPORTS_PER_SOL);
1392+
await connection.confirmTransaction({ signature: airdropSignature, ...(await connection.getLatestBlockhash()) });
1393+
1394+
const mintAuthority = Keypair.generate();
1395+
const decimals = 9;
1396+
const mint = await createMint(
1397+
connection,
1398+
payer,
1399+
mintAuthority.publicKey,
1400+
mintAuthority.publicKey,
1401+
decimals,
1402+
undefined,
1403+
undefined,
1404+
TOKEN_2022_PROGRAM_ID
1405+
);
1406+
1407+
const accountLen = getAccountLen([ExtensionType.CpiGuard]);
1408+
const lamports = await connection.getMinimumBalanceForRentExemption(accountLen);
1409+
1410+
const owner = Keypair.generate();
1411+
const destinationKeypair = Keypair.generate();
1412+
const destination = destinationKeypair.publicKey;
1413+
const transaction = new Transaction().add(
1414+
SystemProgram.createAccount({
1415+
fromPubkey: payer.publicKey,
1416+
newAccountPubkey: destination,
1417+
space: accountLen,
1418+
lamports,
1419+
programId: TOKEN_2022_PROGRAM_ID,
1420+
}),
1421+
createInitializeAccountInstruction(destination, mint, owner.publicKey, TOKEN_2022_PROGRAM_ID),
1422+
createEnableCpiGuardInstruction(destination, owner.publicKey, [], TOKEN_2022_PROGRAM_ID)
1423+
);
1424+
1425+
await sendAndConfirmTransaction(connection, transaction, [payer, owner, destinationKeypair], undefined);
1426+
1427+
// OR
1428+
await enableCpiGuard(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID);
1429+
})();
1430+
```
1431+
</TabItem>
1432+
</Tabs>
1433+
1434+
#### Example: Disable CPI Guard on a token account
1435+
1436+
<Tabs className="unique-tabs" groupId="language-selection">
1437+
<TabItem value="cli" label="CLI" default>
1438+
```console
1439+
$ spl-token disable-cpi-guard 4YfkXX89TrsWqSSxb3av36Rk8EZBoDqxGzuaDNXr7UnL
1440+
1441+
Signature: 4JJSBSc1UAtArbBqYRpTk9264WwJuZ8n6NqyXtCSmyVQpmHoetzyVDwHxtxrdK8wQawoocDxFD9rRPhpAMzJ6EdG
1442+
```
1443+
</TabItem>
1444+
<TabItem value="jsx" label="JS">
1445+
```jsx
1446+
await disableCpiGuard(connection, payer, destination, owner, [], undefined, TOKEN_2022_PROGRAM_ID);
1447+
```
1448+
</TabItem>
1449+
</Tabs>
1450+
13111451
### Transfer Hook
13121452

13131453
#### Motivation

0 commit comments

Comments
 (0)