Skip to content

Commit

Permalink
Increase anchor to 0.30.1 & Add support for group/member token extens…
Browse files Browse the repository at this point in the history
…ions (#18)

* Increase anchor to 0.30.1

* Implement support for GroupPointer & GroupMemberPointer

* Minor

* Remove support for Group & GroupMember

* Add changelog

* Update changelog
  • Loading branch information
tiendv89 authored and andrewsource147 committed Oct 24, 2024
1 parent 6b3ce1c commit 55be9b5
Show file tree
Hide file tree
Showing 10 changed files with 144 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-pr-main-program.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:
env:
SOLANA_CLI_VERSION: 1.18.21
NODE_VERSION: 18.14.2
ANCHOR_CLI_VERSION: 0.29.0
ANCHOR_CLI_VERSION: 0.30.1

jobs:
program_changed_files:
Expand Down
18 changes: 13 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Breaking Changes

## Program [0.3.0] [PR #5](https://github.com/jup-ag/jup-lock/pull/5) [PR #15](https://github.com/jup-ag/jup-lock/pull/15)
## Program [0.3.0] [PR #5](https://github.com/jup-ag/jup-lock/pull/5) [PR #15](https://github.com/jup-ag/jup-lock/pull/15) [PR #18](https://github.com/jup-ag/jup-lock/pull/18)

### Breaking Changes

- Endpoint `create_vesting_escrow` add `cancel_mode` to indicates who can cancel the escrow.

### Changed

- Bump `anchor` version to 0.30.1

### Added

- escrow state add `token_program_flag` to indicates the token program used within the escrow.
- escrow state add `cancelled_at` to indicates the timestamp of the cancellation.
- Add new instruction `cancel_vesting_escrow`, which will cancel the escrow and close the `escrow_token` token account. The claimable amount will be transferred to recipient and the remaining amount will be transferred to creator. The instruction supports both `splToken` and `token2022`.
- Add new v2 instructions to support `token2022` extensions, including: `TransferFeeConfig`, `TokenMetadata`, `MetadataPointer`, `ConfidentialTransferMint`, `ConfidentialTransferFeeConfig`, `PermanentDelegate`, `TransferHook`, `MintCloseAuthority`, `DefaultAccountState` for Token Mint and `MemoTransfer` for Token Account extensions
- `create_vesting_escrow_v2` to create the escrow relevant accounts.
- `claim_v2` to claim from the escrow.
- Add new instruction `cancel_vesting_escrow`, which will cancel the escrow and close the `escrow_token` token account.
The claimable amount will be transferred to recipient and the remaining amount will be transferred to creator. The
instruction supports both `splToken` and `token2022`.
- Add new v2 instructions to support `token2022` extensions,
including: `TransferFeeConfig`, `TokenMetadata`, `MetadataPointer`, `ConfidentialTransferMint`, `ConfidentialTransferFeeConfig`, `PermanentDelegate`, `TransferHook`, `MintCloseAuthority`, `DefaultAccountState`, `GroupPointer`, `GroupMemberPointer`
for Token Mint and `MemoTransfer` for Token Account extensions
- `create_vesting_escrow_v2` to create the escrow relevant accounts.
- `claim_v2` to claim from the escrow.

## Program [0.2.2] [PR #8](https://github.com/jup-ag/jup-lock/pull/8)

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check"
},
"dependencies": {
"@coral-xyz/anchor": "^0.29.0",
"@solana/spl-token": "^0.4.1",
"@coral-xyz/anchor": "^0.30.1",
"@solana/spl-token": "^0.4.8",
"tiny-invariant": "^1.3.3"
},
"devDependencies": {
Expand Down
8 changes: 4 additions & 4 deletions programs/locker/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ cpi = ["no-entrypoint"]
default = []
localnet = []
staging = []
idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]

[dependencies]
anchor-lang = { version = "0.29.0", features = ["event-cpi"] }
anchor-spl = { version = "0.29.0", features = ["memo"] }
anchor-lang = { version = "0.30.1", features = ["event-cpi"] }
anchor-spl = { version = "0.30.1", features = ["memo"] }
spl-transfer-hook-interface = "0.5.0"
solana-program = "1.18.21"
spl-token = { version = "3.5.0", features = ["no-entrypoint"] }
Expand All @@ -29,5 +30,4 @@ static_assertions = "1.1.0"
num_enum = "0.7.1"

[dev-dependencies]
proptest = "1.2.0"
spl-pod = "0.1.0"
proptest = "1.2.0"
15 changes: 10 additions & 5 deletions programs/locker/src/util/token2022.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use anchor_lang::prelude::*;
use anchor_spl::memo;
use anchor_spl::memo::{BuildMemo, Memo};
use anchor_spl::token::Token;
use anchor_spl::token_2022::spl_token_2022::extension::transfer_fee::{
TransferFee, TransferFeeConfig, MAX_FEE_BASIS_POINTS,
};
use anchor_spl::token_2022::spl_token_2022::{
self,
extension::{self, StateWithExtensions},
};
use anchor_spl::token_interface::spl_token_2022::extension::BaseStateWithExtensions;
use anchor_spl::token_2022::spl_token_2022::extension::transfer_fee::{
MAX_FEE_BASIS_POINTS, TransferFee, TransferFeeConfig,
};
use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface};
use anchor_spl::token_interface::spl_token_2022::extension::BaseStateWithExtensions;

use crate::{LockerError, VestingEscrow};

Expand Down Expand Up @@ -179,6 +179,11 @@ pub fn validate_mint(token_mint: &InterfaceAccount<Mint>) -> Result<()> {
extension::ExtensionType::TransferHook => {}
extension::ExtensionType::MintCloseAuthority => {}
extension::ExtensionType::DefaultAccountState => {}
extension::ExtensionType::GroupMemberPointer => {}
extension::ExtensionType::GroupPointer => {}
// Not stable yet to support
// extension::ExtensionType::TokenGroup => {}
// extension::ExtensionType::TokenGroupMember => {}
// mint has unknown or unsupported extensions
_ => {
return Err(LockerError::UnsupportedMint.into());
Expand Down Expand Up @@ -280,8 +285,8 @@ pub fn calculate_pre_fee_amount(transfer_fee: &TransferFee, post_fee_amount: u64

#[cfg(test)]
mod token2022_tests {
use anchor_spl::token_interface::spl_pod::primitives::{PodU16, PodU64};
use proptest::prelude::*;
use spl_pod::primitives::{PodU16, PodU64};

use super::*;

Expand Down
23 changes: 17 additions & 6 deletions tests/locker_utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { AnchorProvider, BN, Program, Wallet, web3 } from "@coral-xyz/anchor";
import { IDL as LockerIDL, Locker } from "../../target/types/locker";
import {
AnchorProvider,
BN,
Program,
Wallet,
web3,
workspace,
} from "@coral-xyz/anchor";
import { Locker } from "../../target/types/locker";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
createAssociatedTokenAccountInstruction,
Expand Down Expand Up @@ -31,8 +38,8 @@ export function createLockerProgram(wallet?: Wallet): Program<Locker> {
maxRetries: 3,
});
provider.opts.commitment = "confirmed";
const program = new Program<Locker>(LockerIDL, LOCKER_PROGRAM_ID, provider);
return program;

return workspace.Locker as Program<Locker>;
}

export function deriveEscrow(base: web3.PublicKey, programId: web3.PublicKey) {
Expand Down Expand Up @@ -139,7 +146,7 @@ export async function createVestingPlan(params: CreateVestingPlanParams) {
ASSOCIATED_TOKEN_PROGRAM_ID
),
])
.signers([baseKP])
.signers([baseKP, ownerKeypair])
.rpc();

if (isAssertion) {
Expand Down Expand Up @@ -197,6 +204,7 @@ export async function claimToken(params: ClaimTokenParams) {
recipient: recipient.publicKey,
recipientToken,
})
.signers([recipient])
.rpc();
}

Expand Down Expand Up @@ -236,6 +244,7 @@ export async function createEscrowMetadata(params: CreateEscrowMetadataParams) {
creator: creator.publicKey,
escrowMetadata,
})
.signers([creator])
.rpc();

if (isAssertion) {
Expand Down Expand Up @@ -278,6 +287,7 @@ export async function updateRecipient(params: UpdateRecipientParams) {
signer: signer.publicKey,
systemProgram: web3.SystemProgram.programId,
})
.signers([signer])
.rpc();

if (isAssertion) {
Expand Down Expand Up @@ -390,7 +400,7 @@ export async function createVestingPlanV2(params: CreateVestingPlanParams) {
ASSOCIATED_TOKEN_PROGRAM_ID
),
])
.signers([baseKP])
.signers([baseKP, ownerKeypair])
.rpc();

if (isAssertion) {
Expand Down Expand Up @@ -569,6 +579,7 @@ export async function cancelVestingPlan(
}),
])
.remainingAccounts(remainingAccounts ? remainingAccounts : [])
.signers([signer])
.rpc();

if (isAssertion) {
Expand Down
48 changes: 46 additions & 2 deletions tests/locker_utils/token_2022/mint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
ASSOCIATED_TOKEN_PROGRAM_ID,
createAssociatedTokenAccountIdempotent,
createInitializeDefaultAccountStateInstruction,
createInitializeGroupMemberPointerInstruction,
createInitializeGroupPointerInstruction,
createInitializeInterestBearingMintInstruction,
createInitializeMintCloseAuthorityInstruction,
createInitializeMintInstruction,
Expand Down Expand Up @@ -71,7 +73,7 @@ export async function createMintTransaction(
let transferFeeConfigAuthority = new web3.Keypair();
let withdrawWithheldAuthority = new web3.Keypair();

let { instructions, postInstructions, additionalLength } =
let { instructions, postInstructions, additionalLength, rentReserveSpace } =
createExtensionMintIx(
extensions,
UserKP,
Expand All @@ -82,7 +84,9 @@ export async function createMintTransaction(

let mintLen = getMintLen(extensions) + additionalLength;
const mintLamports =
await provider.connection.getMinimumBalanceForRentExemption(mintLen);
await provider.connection.getMinimumBalanceForRentExemption(
mintLen + rentReserveSpace
);

const mintTransaction = new Transaction().add(
SystemProgram.createAccount({
Expand Down Expand Up @@ -163,11 +167,13 @@ function createExtensionMintIx(
instructions: web3.TransactionInstruction[];
postInstructions: web3.TransactionInstruction[];
additionalLength: number;
rentReserveSpace: number;
} {
const ix = [];
const postIx = [];
let confidentialTransferMintSizePatch = 0;
let confidentialTransferFeeConfigSizePatch = 0;
let groupPointerSize = 0;

if (extensions.includes(ExtensionType.TransferFeeConfig)) {
ix.push(
Expand Down Expand Up @@ -275,12 +281,50 @@ function createExtensionMintIx(
);
}

if (extensions.includes(ExtensionType.GroupPointer)) {
ix.push(
createInitializeGroupPointerInstruction(
TOKEN,
UserKP.publicKey,
TOKEN,
TOKEN_2022_PROGRAM_ID
)
);

// This extension is not yet stable
// Trying this https://solana.com/developers/courses/token-extensions/group-member#lab
// However, the instruction always failed with error 0xc.
// groupPointerSize = TOKEN_GROUP_SIZE;
// postIx.push(
// createInitializeGroupInstruction({
// group: TOKEN,
// maxSize: 10,
// mint: TOKEN,
// mintAuthority: UserKP.publicKey,
// programId: TOKEN_2022_PROGRAM_ID,
// updateAuthority: UserKP.publicKey,
// })
// );
}

if (extensions.includes(ExtensionType.GroupMemberPointer)) {
ix.push(
createInitializeGroupMemberPointerInstruction(
TOKEN,
UserKP.publicKey,
TOKEN,
TOKEN_2022_PROGRAM_ID
)
);
}

return {
instructions: ix,
postInstructions: postIx,
additionalLength:
confidentialTransferMintSizePatch +
confidentialTransferFeeConfigSizePatch,
rentReserveSpace: groupPointerSize,
};
}

Expand Down
18 changes: 17 additions & 1 deletion tests/v2/test_extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import { BN } from "bn.js";
import { createAndFundWallet, getCurrentBlockTime, sleep } from "../common";
import {
claimTokenV2,
createVestingPlanV2,
createLockerProgram,
createVestingPlanV2,
} from "../locker_utils";
import { assert } from "chai";
import { ADMIN, createMintTransaction } from "../locker_utils/token_2022/mint";
Expand Down Expand Up @@ -129,6 +129,22 @@ describe("[V2] Test supported/unsupported Token Mint", () => {
await check(TOKEN);
});

it("GroupPointer", async () => {
let extensions = [ExtensionType.GroupPointer];

TOKEN = await createMintTransaction(provider, UserKP, extensions);

await check(TOKEN);
});

it("GroupMemberPointer", async () => {
let extensions = [ExtensionType.GroupMemberPointer];

TOKEN = await createMintTransaction(provider, UserKP, extensions);

await check(TOKEN);
});

async function check(TOKEN: web3.PublicKey, errorMsg = "Unsupported mint") {
const program = createLockerProgram(new anchor.Wallet(UserKP));
let currentBlockTime = await getCurrentBlockTime(
Expand Down
26 changes: 17 additions & 9 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
{
"compilerOptions": {
"types": ["mocha", "chai"],
"typeRoots": ["./node_modules/@types"],
"lib": ["es2015"],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true
}
}
"compilerOptions": {
"types": [
"mocha",
"chai"
],
"typeRoots": [
"./node_modules/@types"
],
"lib": [
"es2015"
],
"module": "commonjs",
"target": "es6",
"esModuleInterop": true,
"resolveJsonModule": true
}
}

Loading

0 comments on commit 55be9b5

Please sign in to comment.