@solana/instructions 6.3.1 → 6.3.2-canary-20260313112147
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -4
- package/src/accounts.ts +92 -0
- package/src/index.ts +7 -0
- package/src/instruction.ts +129 -0
- package/src/roles.ts +105 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solana/instructions",
|
|
3
|
-
"version": "6.3.
|
|
3
|
+
"version": "6.3.2-canary-20260313112147",
|
|
4
4
|
"description": "Helpers for creating transaction instructions",
|
|
5
5
|
"homepage": "https://www.solanakit.com/api#solanainstructions",
|
|
6
6
|
"exports": {
|
|
@@ -33,7 +33,8 @@
|
|
|
33
33
|
"types": "./dist/types/index.d.ts",
|
|
34
34
|
"type": "commonjs",
|
|
35
35
|
"files": [
|
|
36
|
-
"./dist/"
|
|
36
|
+
"./dist/",
|
|
37
|
+
"./src/"
|
|
37
38
|
],
|
|
38
39
|
"sideEffects": false,
|
|
39
40
|
"keywords": [
|
|
@@ -55,8 +56,8 @@
|
|
|
55
56
|
"maintained node versions"
|
|
56
57
|
],
|
|
57
58
|
"dependencies": {
|
|
58
|
-
"@solana/codecs-core": "6.3.
|
|
59
|
-
"@solana/errors": "6.3.
|
|
59
|
+
"@solana/codecs-core": "6.3.2-canary-20260313112147",
|
|
60
|
+
"@solana/errors": "6.3.2-canary-20260313112147"
|
|
60
61
|
},
|
|
61
62
|
"peerDependencies": {
|
|
62
63
|
"typescript": "^5.0.0"
|
package/src/accounts.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Address } from '@solana/addresses';
|
|
2
|
+
|
|
3
|
+
import { AccountRole } from './roles';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents an account's address and metadata about its mutability and whether it must be a signer
|
|
7
|
+
* of the transaction.
|
|
8
|
+
*
|
|
9
|
+
* Typically, you will use one of its subtypes.
|
|
10
|
+
*
|
|
11
|
+
* | | `role` | `isSigner` | `isWritable` |
|
|
12
|
+
* | --------------------------------- | ----------------------------- | ---------- | ------------ |
|
|
13
|
+
* | `ReadonlyAccount<TAddress>` | `AccountRole.READONLY` | No | No |
|
|
14
|
+
* | `WritableAccount<TAddress>` | `AccountRole.WRITABLE` | No | Yes |
|
|
15
|
+
* | `ReadonlySignerAccount<TAddress>` | `AccountRole.READONLY_SIGNER` | Yes | No |
|
|
16
|
+
* | `WritableSignerAccount<TAddress>` | `AccountRole.WRITABLE_SIGNER` | Yes | Yes |
|
|
17
|
+
*
|
|
18
|
+
* @example A type for the Rent sysvar account
|
|
19
|
+
* ```ts
|
|
20
|
+
* type RentSysvar = ReadonlyAccount<'SysvarRent111111111111111111111111111111111'>;
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export interface AccountMeta<TAddress extends string = string> {
|
|
24
|
+
readonly address: Address<TAddress>;
|
|
25
|
+
readonly role: AccountRole;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @see {@link AccountMeta}
|
|
30
|
+
*/
|
|
31
|
+
export type ReadonlyAccount<TAddress extends string = string> = AccountMeta<TAddress> & {
|
|
32
|
+
readonly role: AccountRole.READONLY;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @see {@link AccountMeta}
|
|
36
|
+
*/
|
|
37
|
+
export type WritableAccount<TAddress extends string = string> = AccountMeta<TAddress> & { role: AccountRole.WRITABLE };
|
|
38
|
+
/**
|
|
39
|
+
* @see {@link AccountMeta}
|
|
40
|
+
*/
|
|
41
|
+
export type ReadonlySignerAccount<TAddress extends string = string> = AccountMeta<TAddress> & {
|
|
42
|
+
role: AccountRole.READONLY_SIGNER;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* @see {@link AccountMeta}
|
|
46
|
+
*/
|
|
47
|
+
export type WritableSignerAccount<TAddress extends string = string> = AccountMeta<TAddress> & {
|
|
48
|
+
role: AccountRole.WRITABLE_SIGNER;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Represents a lookup of the account's address in an address lookup table. It specifies which
|
|
53
|
+
* lookup table account in which to perform the lookup, the index of the desired account address in
|
|
54
|
+
* that table, and metadata about its mutability. Notably, account addresses obtained via lookups
|
|
55
|
+
* may not act as signers.
|
|
56
|
+
*
|
|
57
|
+
* Typically, you will use one of its subtypes.
|
|
58
|
+
*
|
|
59
|
+
* | | `role` | `isSigner` | `isWritable` |
|
|
60
|
+
* | ------------------------------------------------------ | ---------------------- | ---------- | ------------ |
|
|
61
|
+
* | `ReadonlyLookupAccount<TAddress, TLookupTableAddress>` | `AccountRole.READONLY` | No | No |
|
|
62
|
+
* | `WritableLookupAccount<TAddress, TLookupTableAddress>` | `AccountRole.WRITABLE` | No | Yes |
|
|
63
|
+
*
|
|
64
|
+
* @example A type for the Rent sysvar account that you looked up in a lookup table
|
|
65
|
+
* ```ts
|
|
66
|
+
* type RentSysvar = ReadonlyLookupAccount<
|
|
67
|
+
* 'SysvarRent111111111111111111111111111111111',
|
|
68
|
+
* 'MyLookupTable111111111111111111111111111111'
|
|
69
|
+
* >;
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
export interface AccountLookupMeta<TAddress extends string = string, TLookupTableAddress extends string = string> {
|
|
73
|
+
readonly address: Address<TAddress>;
|
|
74
|
+
readonly addressIndex: number;
|
|
75
|
+
readonly lookupTableAddress: Address<TLookupTableAddress>;
|
|
76
|
+
readonly role: AccountRole.READONLY | AccountRole.WRITABLE;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @see {@link AccountLookupMeta}
|
|
81
|
+
*/
|
|
82
|
+
export type ReadonlyAccountLookup<
|
|
83
|
+
TAddress extends string = string,
|
|
84
|
+
TLookupTableAddress extends string = string,
|
|
85
|
+
> = AccountLookupMeta<TAddress, TLookupTableAddress> & { readonly role: AccountRole.READONLY };
|
|
86
|
+
/**
|
|
87
|
+
* @see {@link AccountLookupMeta}
|
|
88
|
+
*/
|
|
89
|
+
export type WritableAccountLookup<
|
|
90
|
+
TAddress extends string = string,
|
|
91
|
+
TLookupTableAddress extends string = string,
|
|
92
|
+
> = AccountLookupMeta<TAddress, TLookupTableAddress> & { readonly role: AccountRole.WRITABLE };
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This package contains types for creating transaction instructions. It can be used standalone, but it is also exported as part of Kit [`@solana/kit`](https://github.com/anza-xyz/kit/tree/main/packages/kit).
|
|
3
|
+
* @packageDocumentation
|
|
4
|
+
*/
|
|
5
|
+
export * from './accounts';
|
|
6
|
+
export * from './instruction';
|
|
7
|
+
export * from './roles';
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { Address } from '@solana/addresses';
|
|
2
|
+
import { ReadonlyUint8Array } from '@solana/codecs-core';
|
|
3
|
+
import {
|
|
4
|
+
SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_ACCOUNTS,
|
|
5
|
+
SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_DATA,
|
|
6
|
+
SOLANA_ERROR__INSTRUCTION__PROGRAM_ID_MISMATCH,
|
|
7
|
+
SolanaError,
|
|
8
|
+
} from '@solana/errors';
|
|
9
|
+
|
|
10
|
+
import { AccountLookupMeta, AccountMeta } from './accounts';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* An instruction destined for a given program.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* type StakeProgramInstruction = Instruction<'StakeConfig11111111111111111111111111111111'>;
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export interface Instruction<
|
|
21
|
+
TProgramAddress extends string = string,
|
|
22
|
+
TAccounts extends readonly (AccountLookupMeta | AccountMeta)[] = readonly (AccountLookupMeta | AccountMeta)[],
|
|
23
|
+
> {
|
|
24
|
+
readonly accounts?: TAccounts;
|
|
25
|
+
readonly data?: ReadonlyUint8Array;
|
|
26
|
+
readonly programAddress: Address<TProgramAddress>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* An instruction that loads certain accounts.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* type InstructionWithTwoAccounts = InstructionWithAccounts<
|
|
35
|
+
* [
|
|
36
|
+
* WritableAccount, // First account
|
|
37
|
+
* RentSysvar, // Second account
|
|
38
|
+
* ]
|
|
39
|
+
* >;
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export interface InstructionWithAccounts<
|
|
43
|
+
TAccounts extends readonly (AccountLookupMeta | AccountMeta)[],
|
|
44
|
+
> extends Instruction {
|
|
45
|
+
readonly accounts: TAccounts;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function isInstructionForProgram<TProgramAddress extends string, TInstruction extends Instruction>(
|
|
49
|
+
instruction: TInstruction,
|
|
50
|
+
programAddress: Address<TProgramAddress>,
|
|
51
|
+
): instruction is TInstruction & { programAddress: Address<TProgramAddress> } {
|
|
52
|
+
return instruction.programAddress === programAddress;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function assertIsInstructionForProgram<TProgramAddress extends string, TInstruction extends Instruction>(
|
|
56
|
+
instruction: TInstruction,
|
|
57
|
+
programAddress: Address<TProgramAddress>,
|
|
58
|
+
): asserts instruction is TInstruction & { programAddress: Address<TProgramAddress> } {
|
|
59
|
+
if (instruction.programAddress !== programAddress) {
|
|
60
|
+
throw new SolanaError(SOLANA_ERROR__INSTRUCTION__PROGRAM_ID_MISMATCH, {
|
|
61
|
+
actualProgramAddress: instruction.programAddress,
|
|
62
|
+
expectedProgramAddress: programAddress,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function isInstructionWithAccounts<
|
|
68
|
+
TAccounts extends readonly (AccountLookupMeta | AccountMeta)[] = readonly (AccountLookupMeta | AccountMeta)[],
|
|
69
|
+
TInstruction extends Instruction = Instruction,
|
|
70
|
+
>(instruction: TInstruction): instruction is InstructionWithAccounts<TAccounts> & TInstruction {
|
|
71
|
+
return instruction.accounts !== undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function assertIsInstructionWithAccounts<
|
|
75
|
+
TAccounts extends readonly (AccountLookupMeta | AccountMeta)[] = readonly (AccountLookupMeta | AccountMeta)[],
|
|
76
|
+
TInstruction extends Instruction = Instruction,
|
|
77
|
+
>(instruction: TInstruction): asserts instruction is InstructionWithAccounts<TAccounts> & TInstruction {
|
|
78
|
+
if (instruction.accounts === undefined) {
|
|
79
|
+
throw new SolanaError(SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_ACCOUNTS, {
|
|
80
|
+
data: instruction.data,
|
|
81
|
+
programAddress: instruction.programAddress,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* An instruction whose data conforms to a certain type.
|
|
88
|
+
*
|
|
89
|
+
* This is most useful when you have a branded `Uint8Array` that represents a particular
|
|
90
|
+
* instruction's data.
|
|
91
|
+
*
|
|
92
|
+
* @example A type for the \`AdvanceNonce\` instruction of the System program
|
|
93
|
+
* ```ts
|
|
94
|
+
* type AdvanceNonceAccountInstruction<
|
|
95
|
+
* TNonceAccountAddress extends string = string,
|
|
96
|
+
* TNonceAuthorityAddress extends string = string,
|
|
97
|
+
* > = Instruction<'11111111111111111111111111111111'> &
|
|
98
|
+
* InstructionWithAccounts<
|
|
99
|
+
* [
|
|
100
|
+
* WritableAccount<TNonceAccountAddress>,
|
|
101
|
+
* ReadonlyAccount<'SysvarRecentB1ockHashes11111111111111111111'>,
|
|
102
|
+
* ReadonlySignerAccount<TNonceAuthorityAddress>,
|
|
103
|
+
* ]
|
|
104
|
+
* > &
|
|
105
|
+
* InstructionWithData<AdvanceNonceAccountInstructionData>;
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export interface InstructionWithData<TData extends ReadonlyUint8Array> extends Instruction {
|
|
109
|
+
readonly data: TData;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function isInstructionWithData<
|
|
113
|
+
TData extends ReadonlyUint8Array = ReadonlyUint8Array,
|
|
114
|
+
TInstruction extends Instruction = Instruction,
|
|
115
|
+
>(instruction: TInstruction): instruction is InstructionWithData<TData> & TInstruction {
|
|
116
|
+
return instruction.data !== undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function assertIsInstructionWithData<
|
|
120
|
+
TData extends ReadonlyUint8Array = ReadonlyUint8Array,
|
|
121
|
+
TInstruction extends Instruction = Instruction,
|
|
122
|
+
>(instruction: TInstruction): asserts instruction is InstructionWithData<TData> & TInstruction {
|
|
123
|
+
if (instruction.data === undefined) {
|
|
124
|
+
throw new SolanaError(SOLANA_ERROR__INSTRUCTION__EXPECTED_TO_HAVE_DATA, {
|
|
125
|
+
accountAddresses: instruction.accounts?.map(a => a.address),
|
|
126
|
+
programAddress: instruction.programAddress,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
package/src/roles.ts
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Describes the purpose for which an account participates in a transaction.
|
|
3
|
+
*
|
|
4
|
+
* Every account that participates in a transaction can be read from, but only ones that you mark as
|
|
5
|
+
* writable may be written to, and only ones that you indicate must sign the transaction will gain
|
|
6
|
+
* the privileges associated with signers at runtime.
|
|
7
|
+
*
|
|
8
|
+
* | | `isSigner` | `isWritable` |
|
|
9
|
+
* | ----------------------------- | ---------- | ------------ |
|
|
10
|
+
* | `AccountRole.READONLY` | ❌ | ❌ |
|
|
11
|
+
* | `AccountRole.WRITABLE` | ❌ | ✅ |
|
|
12
|
+
* | `AccountRole.READONLY_SIGNER` | ✅ | ❌ |
|
|
13
|
+
* | `AccountRole.WRITABLE_SIGNER` | ✅ | ✅ |
|
|
14
|
+
*/
|
|
15
|
+
export enum AccountRole {
|
|
16
|
+
// Bitflag guide: is signer ⌄⌄ is writable
|
|
17
|
+
WRITABLE_SIGNER = /* 3 */ 0b11, // prettier-ignore
|
|
18
|
+
READONLY_SIGNER = /* 2 */ 0b10, // prettier-ignore
|
|
19
|
+
WRITABLE = /* 1 */ 0b01, // prettier-ignore
|
|
20
|
+
READONLY = /* 0 */ 0b00, // prettier-ignore
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Quick primer on bitwise operations: https://stackoverflow.com/a/1436448/802047
|
|
24
|
+
const IS_SIGNER_BITMASK = 0b10;
|
|
25
|
+
const IS_WRITABLE_BITMASK = 0b01;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @returns An {@link AccountRole} representing the non-signer variant of the supplied role.
|
|
29
|
+
*/
|
|
30
|
+
export function downgradeRoleToNonSigner(role: AccountRole.READONLY_SIGNER): AccountRole.READONLY;
|
|
31
|
+
export function downgradeRoleToNonSigner(role: AccountRole.WRITABLE_SIGNER): AccountRole.WRITABLE;
|
|
32
|
+
export function downgradeRoleToNonSigner(role: AccountRole): AccountRole;
|
|
33
|
+
export function downgradeRoleToNonSigner(role: AccountRole): AccountRole {
|
|
34
|
+
return role & ~IS_SIGNER_BITMASK;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @returns An {@link AccountRole} representing the read-only variant of the supplied role.
|
|
39
|
+
*/
|
|
40
|
+
export function downgradeRoleToReadonly(role: AccountRole.WRITABLE): AccountRole.READONLY;
|
|
41
|
+
export function downgradeRoleToReadonly(role: AccountRole.WRITABLE_SIGNER): AccountRole.READONLY_SIGNER;
|
|
42
|
+
export function downgradeRoleToReadonly(role: AccountRole): AccountRole;
|
|
43
|
+
export function downgradeRoleToReadonly(role: AccountRole): AccountRole {
|
|
44
|
+
return role & ~IS_WRITABLE_BITMASK;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns `true` if the {@link AccountRole} given represents that of a signer. Also refines the
|
|
49
|
+
* TypeScript type of the supplied role.
|
|
50
|
+
*/
|
|
51
|
+
export function isSignerRole(role: AccountRole): role is AccountRole.READONLY_SIGNER | AccountRole.WRITABLE_SIGNER {
|
|
52
|
+
return role >= AccountRole.READONLY_SIGNER;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Returns `true` if the {@link AccountRole} given represents that of a writable account. Also
|
|
57
|
+
* refines the TypeScript type of the supplied role.
|
|
58
|
+
*/
|
|
59
|
+
export function isWritableRole(role: AccountRole): role is AccountRole.WRITABLE | AccountRole.WRITABLE_SIGNER {
|
|
60
|
+
return (role & IS_WRITABLE_BITMASK) !== 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Given two {@link AccountRole | AccountRoles}, will return the {@link AccountRole} that grants the
|
|
65
|
+
* highest privileges of both.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```ts
|
|
69
|
+
* // Returns `AccountRole.WRITABLE_SIGNER`
|
|
70
|
+
* mergeRoles(AccountRole.READONLY_SIGNER, AccountRole.WRITABLE);
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export function mergeRoles(roleA: AccountRole.WRITABLE, roleB: AccountRole.READONLY_SIGNER): AccountRole.WRITABLE_SIGNER; // prettier-ignore
|
|
74
|
+
export function mergeRoles(roleA: AccountRole.READONLY_SIGNER, roleB: AccountRole.WRITABLE): AccountRole.WRITABLE_SIGNER; // prettier-ignore
|
|
75
|
+
export function mergeRoles(roleA: AccountRole, roleB: AccountRole.WRITABLE_SIGNER): AccountRole.WRITABLE_SIGNER; // prettier-ignore
|
|
76
|
+
export function mergeRoles(roleA: AccountRole.WRITABLE_SIGNER, roleB: AccountRole): AccountRole.WRITABLE_SIGNER; // prettier-ignore
|
|
77
|
+
export function mergeRoles(roleA: AccountRole, roleB: AccountRole.READONLY_SIGNER): AccountRole.READONLY_SIGNER; // prettier-ignore
|
|
78
|
+
export function mergeRoles(roleA: AccountRole.READONLY_SIGNER, roleB: AccountRole): AccountRole.READONLY_SIGNER; // prettier-ignore
|
|
79
|
+
export function mergeRoles(roleA: AccountRole, roleB: AccountRole.WRITABLE): AccountRole.WRITABLE; // prettier-ignore
|
|
80
|
+
export function mergeRoles(roleA: AccountRole.WRITABLE, roleB: AccountRole): AccountRole.WRITABLE; // prettier-ignore
|
|
81
|
+
export function mergeRoles(roleA: AccountRole.READONLY, roleB: AccountRole.READONLY): AccountRole.READONLY; // prettier-ignore
|
|
82
|
+
export function mergeRoles(roleA: AccountRole, roleB: AccountRole): AccountRole; // prettier-ignore
|
|
83
|
+
export function mergeRoles(roleA: AccountRole, roleB: AccountRole): AccountRole {
|
|
84
|
+
return roleA | roleB;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* @returns An {@link AccountRole} representing the signer variant of the supplied role.
|
|
89
|
+
*/
|
|
90
|
+
export function upgradeRoleToSigner(role: AccountRole.READONLY): AccountRole.READONLY_SIGNER;
|
|
91
|
+
export function upgradeRoleToSigner(role: AccountRole.WRITABLE): AccountRole.WRITABLE_SIGNER;
|
|
92
|
+
export function upgradeRoleToSigner(role: AccountRole): AccountRole;
|
|
93
|
+
export function upgradeRoleToSigner(role: AccountRole): AccountRole {
|
|
94
|
+
return role | IS_SIGNER_BITMASK;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @returns An {@link AccountRole} representing the writable variant of the supplied role.
|
|
99
|
+
*/
|
|
100
|
+
export function upgradeRoleToWritable(role: AccountRole.READONLY): AccountRole.WRITABLE;
|
|
101
|
+
export function upgradeRoleToWritable(role: AccountRole.READONLY_SIGNER): AccountRole.WRITABLE_SIGNER;
|
|
102
|
+
export function upgradeRoleToWritable(role: AccountRole): AccountRole;
|
|
103
|
+
export function upgradeRoleToWritable(role: AccountRole): AccountRole {
|
|
104
|
+
return role | IS_WRITABLE_BITMASK;
|
|
105
|
+
}
|