Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ All notable changes to the Aptos TypeScript SDK will be captured in this file. T

# Unreleased

- Add permissioned signer support for FungibleAssetPermission, GasPermission, and NFTPermission using `Ed25519Account`s

# 1.35.0 (2025-02-11)

- Add `MultiEd25519Account` to support the legacy MultiEd25519 authentication scheme.
Expand Down
105 changes: 105 additions & 0 deletions examples/typescript/permission_signer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import {
Ed25519Account,
AbstractedAccount,
FungibleAssetPermission,
AccountAddress,
Aptos,
AptosConfig,
Network,
} from "@aptos-labs/ts-sdk";

// Initialize the Aptos client
const config = new AptosConfig({ network: Network.DEVNET });
const aptos = new Aptos(config);

async function demoPermissions() {
/**
* This would be the account that we want to request permissions from.
* This would come back from the wallet.
*/
const primaryAccount = Ed25519Account.generate();

/**
* This is not a true account on chain, just a key-pair that we will use to
* request permissions. You can save the private key of the delegation account
* and use it later.
*/
const delegationAccount = Ed25519Account.generate();

/**
* We take the delegation account and create an abstract account from it. We
* then use this abstract account to execute transactions on behalf of the
* primary account.
*/
const abstractAccount = AbstractedAccount.fromPermissionedSigner({ signer: delegationAccount });

/**
* This is the transaction that we will use to request permissions. Note that
* we must specify the primary account address and the delegation public key.
* We also must sign the request transactions with the primary account.
*/
const txn1 = await aptos.permissions.requestPermissions({
primaryAccountAddress: primaryAccount.accountAddress,
delegationPublicKey: delegationAccount.publicKey,
permissions: [
FungibleAssetPermission.from({
asset: AccountAddress.A, // Replace with the actual asset address
amount: 10, // Amount of the asset
}),
],
});
const txn1Result = await aptos.signAndSubmitTransaction({
signer: primaryAccount,
transaction: txn1,
});
await aptos.waitForTransaction({ transactionHash: txn1Result.hash });

/**
* This is the transaction that we will use to execute the function on behalf
* of the primary account. Here we are transferring 5 units of the asset to
* another account. Note how the sender is the primary account address and the
* signer is the abstract account.
*/
const txn2 = await aptos.signAndSubmitTransaction({
signer: abstractAccount,
transaction: await aptos.transaction.build.simple({
sender: primaryAccount.accountAddress,
data: {
function: "0x1::primary_fungible_store::transfer",
functionArguments: [AccountAddress.A, "receiver_account_address", 5], // Replace with actual receiver address
typeArguments: ["0x1::fungible_asset::Metadata"],
},
}),
});
const txn2Result = await aptos.waitForTransaction({ transactionHash: txn2.hash, options: { checkSuccess: true } });
console.log("Transaction success:", txn2Result.success);

/**
* This is how we can fetch existing permissions for a delegated account.
* Note, a primary account can have any number of delegated accounts.
*/
const permissions = await aptos.getPermissions({
primaryAccountAddress: primaryAccount.accountAddress,
delegationPublicKey: delegationAccount.publicKey,
filter: FungibleAssetPermission,
});

console.log("Existing permissions:", permissions);

/**
* This is how we can revoke permissions.
*/
const txn3 = await aptos.signAndSubmitTransaction({
signer: primaryAccount,
transaction: await aptos.permissions.revokePermission({
primaryAccountAddress: primaryAccount.accountAddress,
delegationPublicKey: delegationAccount.publicKey,
permissions: [FungibleAssetPermission.revoke({ asset: AccountAddress.A })],
}),
});
const txn3Result = await aptos.waitForTransaction({ transactionHash: txn3.hash });
console.log("Transaction success:", txn3Result.success);
}

// Execute the demo
demoPermissions().catch(console.error);
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
"check-version": "scripts/checkVersion.sh",
"update-version": "scripts/updateVersion.sh && pnpm doc",
"spec": "pnpm build && pnpm _spec",
"_spec": "cucumber-js -p default"
"_spec": "cucumber-js -p default",
"test:permissions": "INITIALIZE_JWK_CONSENSUS=1 jest --collectCoverage=false tests/e2e/transaction/permissionedSigner.test.ts"
},
"dependencies": {
"@aptos-labs/aptos-cli": "^1.0.2",
Expand Down
7 changes: 7 additions & 0 deletions src/api/aptos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Faucet } from "./faucet";
import { FungibleAsset } from "./fungibleAsset";
import { General } from "./general";
import { ANS } from "./ans";
import { Permissions } from "./permissions";
import { Staking } from "./staking";
import { Transaction } from "./transaction";
import { Table } from "./table";
Expand Down Expand Up @@ -43,13 +44,16 @@ import { Experimental } from "./experimental";
* ```
* @group Client
*/

export class Aptos {
readonly config: AptosConfig;

readonly account: Account;

readonly ans: ANS;

readonly permissions: Permissions;

readonly coin: Coin;

readonly digitalAsset: DigitalAsset;
Expand Down Expand Up @@ -100,6 +104,7 @@ export class Aptos {
this.account = new Account(this.config);
this.abstraction = new AccountAbstraction(this.config);
this.ans = new ANS(this.config);
this.permissions = new Permissions(this.config);
this.coin = new Coin(this.config);
this.digitalAsset = new DigitalAsset(this.config);
this.event = new Event(this.config);
Expand All @@ -120,6 +125,7 @@ export class Aptos {
export interface Aptos
extends Account,
ANS,
Permissions,
Coin,
DigitalAsset,
Event,
Expand Down Expand Up @@ -158,6 +164,7 @@ function applyMixin(targetClass: any, baseClass: any, baseClassProp: string) {
applyMixin(Aptos, Account, "account");
applyMixin(Aptos, AccountAbstraction, "abstraction");
applyMixin(Aptos, ANS, "ans");
applyMixin(Aptos, Permissions, "permissions");
applyMixin(Aptos, Coin, "coin");
applyMixin(Aptos, DigitalAsset, "digitalAsset");
applyMixin(Aptos, Event, "event");
Expand Down
120 changes: 120 additions & 0 deletions src/api/permissions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright © Aptos Foundation
// SPDX-License-Identifier: Apache-2.0

import { getPermissions, requestPermission, revokePermissions } from "../internal/permissions";
import { AptosConfig } from "./aptosConfig";
import { SimpleTransaction } from "../transactions/instances/simpleTransaction";
import { Permission } from "../types/permissions";
import { AccountAddress, PublicKey } from "../core";

/**
* Manages permission operations for delegated accounts.
* Handles granting, revoking, and querying permissions for fungible assets, gas, and NFTs.
*/
export class Permissions {
constructor(readonly config: AptosConfig) {}

/**
* Gets current permissions for a delegation key
*
* @example
* ```typescript
* const permissions = await aptos.permissions.getPermissions({
* primaryAccountAddress: AccountAddress.fromString("0x1"),
* delegationPublicKey: delegatedAccount.publicKey
* filter: FungibleAssetPermission
* });
* ```
*/
async getPermissions<T extends Permission>(args: {
primaryAccountAddress: AccountAddress;
delegationPublicKey: PublicKey;
filter?: new (...a: any) => T;
}): Promise<T[]> {
return getPermissions({
aptosConfig: this.config,
primaryAccountAddress: args.primaryAccountAddress,
delegationPublicKey: args.delegationPublicKey,
filter: args.filter,
});
}

/**
* Requests permissions for a delegation key
*
* @param args
* @param args.primaryAccountAddress - The primary account address
* @param args.delegationPublicKey - The delegation public key
* @param args.permissions - The permissions to request
* @param args.expiration - The expiration time of the permissions, in epoch seconds. Defaults to 1 day from now.
* @param args.refreshInterval - The refresh interval of the permissions, in seconds. Defaults to 60 seconds.
* @param args.maxTransactionsPerInterval - The maximum number of transactions per interval. Defaults to 1000.
*
* @example
* ```typescript
* const txn = await aptos.permissions.requestPermissions({
* primaryAccountAddress: AccountAddress.fromString("0x1"),
* delegationPublicKey: delegatedAccount.publicKey,
* permissions: [
* FungibleAssetPermission.from({ asset: AccountAddress.A, amount: 100 })
* ]
* });
*
* await aptos.signAndSubmitTransaction({
* signer: primaryAccount,
* transaction: txn,
* });
* ```
*/
async requestPermissions(args: {
primaryAccountAddress: AccountAddress;
delegationPublicKey: PublicKey;
permissions: Permission[];
expiration?: number;
refreshInterval?: number;
maxTransactionsPerInterval?: number;
}): Promise<SimpleTransaction> {
return requestPermission({
aptosConfig: this.config,
primaryAccountAddress: args.primaryAccountAddress,
delegationPublicKey: args.delegationPublicKey,
permissions: args.permissions,
expiration: args.expiration ?? Date.now() + 24 * 60 * 60 * 1000,
refreshInterval: args.refreshInterval ?? 60,
maxTransactionsPerInterval: args.maxTransactionsPerInterval ?? 1000,
});
}

/**
* Revokes permissions from a delegation key. Note: You can pass an entire permission you get back from `getPermissions`
* or call the static `revoke` function on the permission.
*
* @example
* ```typescript
* const txn = await aptos.permissions.revokePermission({
* primaryAccountAddress: AccountAddress.fromString("0x1"),
* delegationPublicKey: delegatedAccount.publicKey,
* permissions: [
* FungibleAssetPermission.revoke({ asset: AccountAddress.A })
* ]
* });
*
* await aptos.signAndSubmitTransaction({
* signer: primaryAccount,
* transaction: txn,
* });
* ```
*/
async revokePermission(args: {
primaryAccountAddress: AccountAddress;
delegationPublicKey: PublicKey;
permissions: Permission[];
}): Promise<SimpleTransaction> {
return revokePermissions({
aptosConfig: this.config,
primaryAccountAddress: args.primaryAccountAddress,
delegationPublicKey: args.delegationPublicKey,
permissions: args.permissions,
});
}
}
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export * from "./errors";
export * from "./transactions";
export * from "./transactions/management";
export * from "./types";
export * from "./types/permissions";
export * from "./utils";
Loading