Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Permissioned Accounts #594

Draft
wants to merge 5 commits into
base: sub-accounts
Choose a base branch
from
Draft

Conversation

chiumax
Copy link
Member

@chiumax chiumax commented Nov 25, 2024

Description

big thanks to @kaw2k for the help + stubs

Best Practice Questions:

  • Currently types are living under internal/Permissions.ts, should they be moved to api/...ts?

    • Based on the context, types should likely move to api/ since they are part of the public interface
    • This matches the pattern seen in api/permissions.ts which exposes the Permission types
  • Should we remove the factories for each permissions or keep both types and factories?

    • Factories don't provide much value beyond type construction
    • Tests show direct object construction is just as clear
    • Consider deprecating factories in favor of just types

Points of Interest:

  • Issue with returning arrays in grantPermission:
    • NFT permissions can have multiple capabilities (transfer, mutate)
    • Current workaround is handling each capability separately
    • Need to investigate why batched array returns break Move code
    • Consider refactoring NFT permissions into separate permission objects per capability
    • Gas vs APT permissions?

Architecture Changes @kaw2k:

  • Moved core permission functionality from tests to internal/Permissions.ts
  • Updated some of the syntax in the test cases
  • Added proper abstraction layers:
    • api/permissions.ts - Public interface
    • internal/permissions.ts - Implementation
    • tests - Integration testing

Permission Types:

  1. FungibleAssetPermission
  2. Gas Permission
  3. NFT Permission
  4. NFT Collection Permission

Core Features:

  • Request Permission

    • FungibleAsset
    • NFT 🟠
      • mutate
      • 'transfer` ✅
    • Gas
    • NFTCollection
  • Revoke Permission

    • FungibleAsset
    • NFT
    • Gas
    • NFTCollection
  • View Permission

    • FungibleAsset
    • NFT 🟠
      - mutate
      - transfer
    • Gas
    • NFTCollection

TODO:

  • Implement NFT mutate capability
  • Investigate batched permission returns
  • Add proper error handling
  • Consider deprecating permission factories

Test Plan

Related Links

Checklist

  • Have you ran pnpm fmt?
  • Have you updated the CHANGELOG.md?

@chiumax chiumax requested a review from a team as a code owner November 25, 2024 22:07
@chiumax chiumax requested review from kaw2k and hardsetting and removed request for a team November 25, 2024 22:07
@chiumax chiumax marked this pull request as draft November 25, 2024 22:08
@chiumax chiumax changed the base branch from main to sub-accounts November 26, 2024 17:59
],
typeArguments: [],
});
case PermissionType.NFT: {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returning an array here breaks

export type RevokeNFTPermission = Pick<NFTPermission, "type" | "assetAddress">;

// factories -- on second thought, i think these are dumb
export function FungibleAssetPermission(args: Omit<FungibleAssetPermission, "type">): FungibleAssetPermission {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove these?

Comment on lines +48 to +51
export enum MoveVMPermissionType {
FungibleAsset = "0x1::fungible_asset::WithdrawPermission",

}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would technically be a Capability not a permission. Maybe we have the capability types here and for nfts be the actual move vm string so we can re-use them? Need to think on that a moment.

Comment on lines +82 to +85
export interface GenericPermission {
type: Exclude<string, PermissionType | `${PermissionType}`>;
[key: string]: string | Exclude<string, PermissionType | `${PermissionType}`>;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Placeholder: Is this needed?

Comment on lines +114 to +116
export function GenericPermission(args: GenericPermission): GenericPermission {
return {...args}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe move to the test file then.

Comment on lines 120 to 124
export interface PermissionTemp{
asset: string;
type: string;
remaining: string;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove?

Comment on lines +91 to +111
// factories -- on second thought, i think these are dumb
export function FungibleAssetPermission(args: Omit<FungibleAssetPermission, "type">): FungibleAssetPermission {
return { type: PermissionType.FungibleAsset, ...args };
}
export function GasPermission(args: Omit<GasPermission, "type">): GasPermission {
return { type: PermissionType.Gas, ...args };
}
export function NFTPermission(args: Omit<NFTPermission, "type">): NFTPermission {
return { type: PermissionType.NFT, ...args };
}
export function NFTCollectionPermission(args: Omit<NFTCollectionPermission, "type">): NFTCollectionPermission {
return { type: PermissionType.NFTCollection, ...args };
}

// revoke factories
export function RevokeFungibleAssetPermission(args: Omit<RevokeFungibleAssetPermission, "type">): RevokeFungibleAssetPermission {
return { type: PermissionType.FungibleAsset, ...args };
}
export function RevokeNFTPermission(args: Omit<RevokeNFTPermission, "type">): RevokeNFTPermission {
return { type: PermissionType.NFT, ...args };
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main draw here is improved type inference. To get a feel for how it would work without the factories, try consuming requestPermissions without using factories. You open a new object and are left without guidance on what the first step is. A brand new consumer of the API might not find it readily apparent that all the properties are defined based on what type is specified.

Might be good to brainstorm other possible DX around this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should factories be moved to api file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but good point actually

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since they share the same name as the interface, I think having them both be here is fine.

// txn.push(builder.add_batched_calls({
// function: "0x1::object::grant_permission",
// functionArguments: [
// BatchArgument.new_signer(0),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bruh

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the types are getting messed up here due to GenericPermission. The type field of GenericPermission is string which also matches at the type level.

aptosConfig: AptosConfig;
primaryAccount: SingleKeyAccount;
subAccount: AbstractedEd25519Account;
permissions: RevokePermission[];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without putting any thought into this, something feels off here. Need to dig a little.

const { aptosConfig, primaryAccount, subAccount, permissions } = args;

const aptos = new Aptos(aptosConfig);
const transaction = await aptos.transaction.build.batched_intents({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to change this to be the public key as well.

primaryAccount: SingleKeyAccount;
subAccount: AbstractedEd25519Account;
}) {
const aptos = new Aptos(aptosConfig);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.

Comment on lines +53 to +58

}

export interface FungibleAssetPermission {
type: PermissionType.FungibleAsset;
asset: string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's discuss about the two types of fungible permissions (primary store vs fixed amount)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants