# Block Accounts

The Keeta Network uses an Access Control List (ACL) system where token owners can grant or revoke `ACCESS` permissions for individual accounts.&#x20;

This tutorial will guide you through creating a token, granting access to multiple accounts, blocking one specific account, and verifying that the block worked correctly.

## Prerequisites <a href="#prerequisites" id="prerequisites"></a>

Before you begin, ensure you have [Installed the KeetaNet SDK.](/introduction/start-developing.md)

{% stepper %}
{% step %}

### Set Up Your Accounts <a href="#step-1-set-up-your-accounts" id="step-1-set-up-your-accounts"></a>

We generate a random seed to create deterministic accounts for our tutorial. The `tokenOwner` account at index 0 will own and control the token throughout this process. `addressA` at index 1 will be the account we block later to demonstrate the blocking functionality. `addressB` at index 2 will keep access throughout the entire process to show selective blocking.&#x20;

Finally, we create a `UserClient` for the token owner which allows us to perform blockchain operations.

```typescript
import * as KeetaNet from "@keetanetwork/keetanet-client";

async function main() {
    const seed = KeetaNet.lib.Account.generateRandomSeed({ asString: true });

    // Create accounts
    const tokenOwner = KeetaNet.lib.Account.fromSeed(seed, 0);
    const addressA = KeetaNet.lib.Account.fromSeed(seed, 1);
    const addressB = KeetaNet.lib.Account.fromSeed(seed, 2);
    
    const tokenOwnerClient = KeetaNet.UserClient.fromNetwork("test", tokenOwner);

    console.log("Token Owner:", tokenOwner.publicKeyString.toString());
    console.log("Address A:", addressA.publicKeyString.toString()); 
    console.log("Address B:", addressB.publicKeyString.toString());
}
```

{% endstep %}

{% step %}

### Create Your Token <a href="#step-2-create-your-token" id="step-2-create-your-token"></a>

We use the builder pattern to create a new token account on the Keeta Network. The `generateIdentifier()` method creates a new TOKEN-type account with a unique identifier. After calling `computeBlocks()`, we can access the generated token account. The `setInfo()` method defines the token metadata and crucially sets the default `ACCESS` permission, which allows public interaction with the token.&#x20;

We then use `modifyTokenSupply()` to mint 10,000 tokens to the token account. Finally, `publishBuilder()` commits all these changes to the blockchain in a single transaction.

```typescript
console.log("\n=== Creating Token ===");
const builder = tokenOwnerClient.initBuilder();
const pendingToken = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN);
await builder.computeBlocks();
const tokenAccount = pendingToken.account;

builder.setInfo({
    name: '',
    description: '',
    metadata: '',
    defaultPermission: new KeetaNet.lib.Permissions(['ACCESS'])
}, { account: tokenAccount });

builder.modifyTokenSupply(10000n, { account: tokenAccount });
await tokenOwnerClient.publishBuilder(builder);
console.log("✅ Token created with public ACCESS");
```

{% endstep %}

{% step %}

### Grant Access to Specific Addresses <a href="#step-3-grant-access-to-specific-addresses" id="step-3-grant-access-to-specific-addresses"></a>

The `updatePermissions()` method modifies access rights for specific accounts on our token. We use `AdjustMethod.SET` to grant the `ACCESS` permission to each address explicitly.&#x20;

This ensures both addresses have clear, documented access to interact with the token. The `{ account: tokenAccount }` parameter specifies which token we're modifying permissions for.&#x20;

Each call to `updatePermissions()` creates a separate transaction that grants access to the specified address.

```typescript
await tokenOwnerClient.updatePermissions(
    addressA,
    new KeetaNet.lib.Permissions(['ACCESS']),
    tokenAccount,
    KeetaNet.lib.Block.AdjustMethod.SET,
    { account: tokenAccount }
);

await tokenOwnerClient.updatePermissions(
    addressB,
    new KeetaNet.lib.Permissions(['ACCESS']),
    tokenAccount,
    KeetaNet.lib.Block.AdjustMethod.SET,
    { account: tokenAccount }
);
```

{% endstep %}

{% step %}

### Verify Initial Access <a href="#step-4-verify-initial-access" id="step-4-verify-initial-access"></a>

The `listACLsByEntity()` method retrieves all Access Control List entries for our token, showing us every account that has been granted specific permissions. We search through this list to find ACL entries matching each of our test addresses using the `comparePublicKey()` method for secure address comparison.&#x20;

The `permissions.has(['ACCESS'])` method checks whether the ACCESS permission is present in each account's permission set. At this point in the tutorial, both addresses should show `true`, indicating they have access to the token.

```typescript
console.log("\n=== Checking Initial Access ===");
const initialACLs = await tokenOwnerClient.listACLsByEntity({ account: tokenAccount });

const addressA_ACL = initialACLs.find(acl => acl.principal.comparePublicKey(addressA));
const addressB_ACL = initialACLs.find(acl => acl.principal.comparePublicKey(addressB));

const addressA_HasAccess = addressA_ACL && addressA_ACL.permissions.has(['ACCESS']);
const addressB_HasAccess = addressB_ACL && addressB_ACL.permissions.has(['ACCESS']);

console.log("Address A has access:", addressA_HasAccess);
console.log("Address B has access:", addressB_HasAccess);
```

{% endstep %}

{% step %}

### Block a Specific Address <a href="#step-5-block-a-specific-address" id="step-5-block-a-specific-address"></a>

We use the same `updatePermissions()` method as before, but this time with `AdjustMethod.SUBTRACT` instead of `SET`.&#x20;

The `SUBTRACT` method removes the specified permissions from the target account rather than granting them. In this case, we're removing the `ACCESS` permission from Address A, effectively blocking that account from interacting with our token. Only Address A is affected by this operation, while Address B retains all its existing permissions.&#x20;

The blocking takes effect immediately after the transaction is published to the network.

```typescript
console.log("\n=== Blocking Address A ===");
await tokenOwnerClient.updatePermissions(
    addressA,
    new KeetaNet.lib.Permissions(['ACCESS']),
    tokenAccount,
    KeetaNet.lib.Block.AdjustMethod.SUBTRACT,
    { account: tokenAccount }
);
console.log("✅ Address A blocked");
```

{% endstep %}

{% step %}

### Verify the Block Worked <a href="#step-6-verify-the-block-worked" id="step-6-verify-the-block-worked"></a>

We perform the same ACL lookup and permission check as we did in Step 4, but now we can see the results of our blocking operation.&#x20;

Address A should now show `false` when we check for ACCESS permission, indicating it has been successfully blocked.&#x20;

Address B should still show `true`, demonstrating that our blocking was selective and didn't affect other accounts.&#x20;

The summary section provides a clear confirmation that our selective blocking worked correctly by comparing the before and after states of both addresses.

```typescript
console.log("\n=== Verifying Block ===");
const finalACLs = await tokenOwnerClient.listACLsByEntity({ account: tokenAccount });

const final_addressA_ACL = finalACLs.find(acl => acl.principal.comparePublicKey(addressA));
const final_addressB_ACL = finalACLs.find(acl => acl.principal.comparePublicKey(addressB));

const final_addressA_HasAccess = final_addressA_ACL && final_addressA_ACL.permissions.has(['ACCESS']);
const final_addressB_HasAccess = final_addressB_ACL && final_addressB_ACL.permissions.has(['ACCESS']);

console.log("Address A has access after blocking:", final_addressA_HasAccess);
console.log("Address B has access after blocking:", final_addressB_HasAccess);

console.log("\n=== Summary ===");
console.log("Address A blocked successfully:", addressA_HasAccess && !final_addressA_HasAccess);
console.log("Address B still has access:", addressB_HasAccess && final_addressB_HasAccess);
```

{% endstep %}
{% endstepper %}

## Full Code Example

```typescript
import * as KeetaNet from "@keetanetwork/keetanet-client";

async function main() {
    const seed = KeetaNet.lib.Account.generateRandomSeed({ asString: true });

    // Create accounts
    const tokenOwner = KeetaNet.lib.Account.fromSeed(seed, 0);
    const addressA = KeetaNet.lib.Account.fromSeed(seed, 1);
    const addressB = KeetaNet.lib.Account.fromSeed(seed, 2);
    
    const tokenOwnerClient = KeetaNet.UserClient.fromNetwork("test", tokenOwner);

    console.log("Token Owner:", tokenOwner.publicKeyString.toString());
    console.log("Address A:", addressA.publicKeyString.toString()); 
    console.log("Address B:", addressB.publicKeyString.toString());

    // 1. Create token with public access
    console.log("\n=== Creating Token ===");
    const builder = tokenOwnerClient.initBuilder();
    const pendingToken = builder.generateIdentifier(KeetaNet.lib.Account.AccountKeyAlgorithm.TOKEN);
    await builder.computeBlocks();
    const tokenAccount = pendingToken.account;

    builder.setInfo({
        name: '',
        description: '',
        metadata: '',
        defaultPermission: new KeetaNet.lib.Permissions(['ACCESS'])
    }, { account: tokenAccount });

    builder.modifyTokenSupply(10000n, { account: tokenAccount });
    await tokenOwnerClient.publishBuilder(builder);
    console.log("✅ Token created with public ACCESS");

    // 2. Grant explicit access to both addresses
    await tokenOwnerClient.updatePermissions(
        addressA,
        new KeetaNet.lib.Permissions(['ACCESS']),
        tokenAccount,
        KeetaNet.lib.Block.AdjustMethod.SET,
        { account: tokenAccount }
    );

    await tokenOwnerClient.updatePermissions(
        addressB,
        new KeetaNet.lib.Permissions(['ACCESS']),
        tokenAccount,
        KeetaNet.lib.Block.AdjustMethod.SET,
        { account: tokenAccount }
    );

    // 3. Verify both addresses have access
    console.log("\n=== Checking Initial Access ===");
    const initialACLs = await tokenOwnerClient.listACLsByEntity({ account: tokenAccount });
    
    const addressA_ACL = initialACLs.find(acl => acl.principal.comparePublicKey(addressA));
    const addressB_ACL = initialACLs.find(acl => acl.principal.comparePublicKey(addressB));
    
    const addressA_HasAccess = addressA_ACL && addressA_ACL.permissions.has(['ACCESS']);
    const addressB_HasAccess = addressB_ACL && addressB_ACL.permissions.has(['ACCESS']);
    
    console.log("Address A has access:", addressA_HasAccess);
    console.log("Address B has access:", addressB_HasAccess);

    // 4. Block Address A
    console.log("\n=== Blocking Address A ===");
    await tokenOwnerClient.updatePermissions(
        addressA,
        new KeetaNet.lib.Permissions(['ACCESS']),
        tokenAccount,
        KeetaNet.lib.Block.AdjustMethod.SUBTRACT,
        { account: tokenAccount }
    );
    console.log("✅ Address A blocked");

    // 5. Verify blocking worked - A is blocked, B still has access
    console.log("\n=== Verifying Block ===");
    const finalACLs = await tokenOwnerClient.listACLsByEntity({ account: tokenAccount });
    
    const final_addressA_ACL = finalACLs.find(acl => acl.principal.comparePublicKey(addressA));
    const final_addressB_ACL = finalACLs.find(acl => acl.principal.comparePublicKey(addressB));
    
    const final_addressA_HasAccess = final_addressA_ACL && final_addressA_ACL.permissions.has(['ACCESS']);
    const final_addressB_HasAccess = final_addressB_ACL && final_addressB_ACL.permissions.has(['ACCESS']);
    
    console.log("Address A has access after blocking:", final_addressA_HasAccess);
    console.log("Address B has access after blocking:", final_addressB_HasAccess);

    console.log("\n=== Summary ===");
    console.log("Address A blocked successfully:", addressA_HasAccess && !final_addressA_HasAccess);
    console.log("Address B still has access:", addressB_HasAccess && final_addressB_HasAccess);
}

main().catch(console.error);

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeta.com/components/accounts/permissions/block-accounts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
