Skip to content

Commit

Permalink
Fixing transfer permissions.
Browse files Browse the repository at this point in the history
  • Loading branch information
blockiosaurus committed Feb 22, 2024
1 parent 744559b commit e19d598
Show file tree
Hide file tree
Showing 16 changed files with 403 additions and 40 deletions.
143 changes: 143 additions & 0 deletions clients/js/src/generated/accounts/hashedAssetSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/**
* This code was AUTOGENERATED using the kinobi library.
* Please DO NOT EDIT THIS FILE, instead use visitors
* to add features, then rerun kinobi to update it.
*
* @see https://github.com/metaplex-foundation/kinobi
*/

import {
Account,
Context,
Pda,
PublicKey,
RpcAccount,
RpcGetAccountOptions,
RpcGetAccountsOptions,
assertAccountExists,
deserializeAccount,
gpaBuilder,
publicKey as toPublicKey,
} from '@metaplex-foundation/umi';
import {
Serializer,
array,
bytes,
struct,
} from '@metaplex-foundation/umi/serializers';
import { PluginHash, PluginHashArgs, getPluginHashSerializer } from '../types';

export type HashedAssetSchema = Account<HashedAssetSchemaAccountData>;

export type HashedAssetSchemaAccountData = {
assetHash: Uint8Array;
pluginHashes: Array<PluginHash>;
};

export type HashedAssetSchemaAccountDataArgs = {
assetHash: Uint8Array;
pluginHashes: Array<PluginHashArgs>;
};

export function getHashedAssetSchemaAccountDataSerializer(): Serializer<
HashedAssetSchemaAccountDataArgs,
HashedAssetSchemaAccountData
> {
return struct<HashedAssetSchemaAccountData>(
[
['assetHash', bytes({ size: 32 })],
['pluginHashes', array(getPluginHashSerializer())],
],
{ description: 'HashedAssetSchemaAccountData' }
) as Serializer<
HashedAssetSchemaAccountDataArgs,
HashedAssetSchemaAccountData
>;
}

export function deserializeHashedAssetSchema(
rawAccount: RpcAccount
): HashedAssetSchema {
return deserializeAccount(
rawAccount,
getHashedAssetSchemaAccountDataSerializer()
);
}

export async function fetchHashedAssetSchema(
context: Pick<Context, 'rpc'>,
publicKey: PublicKey | Pda,
options?: RpcGetAccountOptions
): Promise<HashedAssetSchema> {
const maybeAccount = await context.rpc.getAccount(
toPublicKey(publicKey, false),
options
);
assertAccountExists(maybeAccount, 'HashedAssetSchema');
return deserializeHashedAssetSchema(maybeAccount);
}

export async function safeFetchHashedAssetSchema(
context: Pick<Context, 'rpc'>,
publicKey: PublicKey | Pda,
options?: RpcGetAccountOptions
): Promise<HashedAssetSchema | null> {
const maybeAccount = await context.rpc.getAccount(
toPublicKey(publicKey, false),
options
);
return maybeAccount.exists
? deserializeHashedAssetSchema(maybeAccount)
: null;
}

export async function fetchAllHashedAssetSchema(
context: Pick<Context, 'rpc'>,
publicKeys: Array<PublicKey | Pda>,
options?: RpcGetAccountsOptions
): Promise<HashedAssetSchema[]> {
const maybeAccounts = await context.rpc.getAccounts(
publicKeys.map((key) => toPublicKey(key, false)),
options
);
return maybeAccounts.map((maybeAccount) => {
assertAccountExists(maybeAccount, 'HashedAssetSchema');
return deserializeHashedAssetSchema(maybeAccount);
});
}

export async function safeFetchAllHashedAssetSchema(
context: Pick<Context, 'rpc'>,
publicKeys: Array<PublicKey | Pda>,
options?: RpcGetAccountsOptions
): Promise<HashedAssetSchema[]> {
const maybeAccounts = await context.rpc.getAccounts(
publicKeys.map((key) => toPublicKey(key, false)),
options
);
return maybeAccounts
.filter((maybeAccount) => maybeAccount.exists)
.map((maybeAccount) =>
deserializeHashedAssetSchema(maybeAccount as RpcAccount)
);
}

export function getHashedAssetSchemaGpaBuilder(
context: Pick<Context, 'rpc' | 'programs'>
) {
const programId = context.programs.getPublicKey(
'mplAsset',
'ASSETp3DinZKfiAyvdQG16YWWLJ2X3ZKjg9zku7n1sZD'
);
return gpaBuilder(context, programId)
.registerFields<{
assetHash: Uint8Array;
pluginHashes: Array<PluginHashArgs>;
}>({
assetHash: [0, bytes({ size: 32 })],
pluginHashes: [32, array(getPluginHashSerializer())],
})
.deserializeUsing<HashedAssetSchema>((account) =>
deserializeHashedAssetSchema(account)
);
}
1 change: 1 addition & 0 deletions clients/js/src/generated/accounts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

export * from './asset';
export * from './hashedAsset';
export * from './hashedAssetSchema';
export * from './pluginHeader';
export * from './pluginRegistry';
26 changes: 26 additions & 0 deletions clients/js/src/generated/errors/mplAsset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,32 @@ export class NumericalOverflowErrorError extends ProgramError {
codeToErrorMap.set(0x10, NumericalOverflowErrorError);
nameToErrorMap.set('NumericalOverflowError', NumericalOverflowErrorError);

/** AlreadyCompressed: Already compressed account */
export class AlreadyCompressedError extends ProgramError {
readonly name: string = 'AlreadyCompressed';

readonly code: number = 0x11; // 17

constructor(program: Program, cause?: Error) {
super('Already compressed account', program, cause);
}
}
codeToErrorMap.set(0x11, AlreadyCompressedError);
nameToErrorMap.set('AlreadyCompressed', AlreadyCompressedError);

/** AlreadyDecompressed: Already decompressed account */
export class AlreadyDecompressedError extends ProgramError {
readonly name: string = 'AlreadyDecompressed';

readonly code: number = 0x12; // 18

constructor(program: Program, cause?: Error) {
super('Already decompressed account', program, cause);
}
}
codeToErrorMap.set(0x12, AlreadyDecompressedError);
nameToErrorMap.set('AlreadyDecompressed', AlreadyDecompressedError);

/**
* Attempts to resolve a custom program error from the provided error code.
* @category Errors
Expand Down
1 change: 1 addition & 0 deletions clients/js/src/generated/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from './freeze';
export * from './key';
export * from './migrationLevel';
export * from './plugin';
export * from './pluginHash';
export * from './pluginType';
export * from './registryData';
export * from './registryRecord';
Expand Down
33 changes: 33 additions & 0 deletions clients/js/src/generated/types/pluginHash.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* This code was AUTOGENERATED using the kinobi library.
* Please DO NOT EDIT THIS FILE, instead use visitors
* to add features, then rerun kinobi to update it.
*
* @see https://github.com/metaplex-foundation/kinobi
*/

import {
Serializer,
bytes,
struct,
} from '@metaplex-foundation/umi/serializers';

export type PluginHash = {
pluginAuthoritiesHash: Uint8Array;
pluginHash: Uint8Array;
};

export type PluginHashArgs = PluginHash;

export function getPluginHashSerializer(): Serializer<
PluginHashArgs,
PluginHash
> {
return struct<PluginHash>(
[
['pluginAuthoritiesHash', bytes({ size: 32 })],
['pluginHash', bytes({ size: 32 })],
],
{ description: 'PluginHash' }
) as Serializer<PluginHashArgs, PluginHash>;
}
95 changes: 60 additions & 35 deletions clients/js/test/delegateTransfer.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { generateSigner } from '@metaplex-foundation/umi';
import test from 'ava';
// import { base58 } from '@metaplex-foundation/umi/serializers';
import { Asset, DataState, create, /* delegate, */ fetchAsset, /* transfer */ } from '../src';
import { AssetWithPlugins, DataState, PluginType, addAuthority, addPlugin, create, fetchAssetWithPlugins, transfer } from '../src';
import { createUmi } from './_setup';

test('it can transfer an asset as the delegate', async (t) => {
test('a delegate can transfer the asset', async (t) => {
// Given a Umi instance and a new signer.
const umi = await createUmi();
const assetAddress = generateSigner(umi);
// const newOwner = generateSigner(umi);
// const delegateAddress = generateSigner(umi);
const delegateAddress = generateSigner(umi);
const newOwnerAddress = generateSigner(umi);

// When we create a new account.
await create(umi, {
Expand All @@ -19,38 +18,64 @@ test('it can transfer an asset as the delegate', async (t) => {
uri: 'https://example.com/bread',
}).sendAndConfirm(umi);

// Then an account was created with the correct data.
const beforeAsset = await fetchAsset(umi, assetAddress.publicKey);
// console.log("Account State:", beforeAsset);
t.like(beforeAsset, <Asset>{
await addPlugin(umi, {
assetAddress: assetAddress.publicKey,
plugin: {
__kind: 'Transfer',
fields: [{}],
}
}).sendAndConfirm(umi);

await addAuthority(umi, {
assetAddress: assetAddress.publicKey,
pluginType: PluginType.Transfer,
newAuthority: {
__kind: 'Pubkey',
address: delegateAddress.publicKey,
}
}).sendAndConfirm(umi);

await transfer(umi, {
assetAddress: assetAddress.publicKey,
newOwner: newOwnerAddress.publicKey,
authority: delegateAddress,
compressionProof: null
}).sendAndConfirm(umi);

const asset = await fetchAssetWithPlugins(umi, assetAddress.publicKey);
// console.log(asset);
t.like(asset, <AssetWithPlugins>{
publicKey: assetAddress.publicKey,
updateAuthority: umi.identity.publicKey,
owner: umi.identity.publicKey,
owner: newOwnerAddress.publicKey,
name: 'Test Bread',
uri: 'https://example.com/bread',
pluginHeader: {
key: 3,
pluginRegistryOffset: BigInt(118),
},
pluginRegistry: {
key: 4,
registry: [{
pluginType: PluginType.Transfer,
data: {
offset: BigInt(117),
authorities: [
{ __kind: "Owner" },
{ __kind: "Pubkey", address: delegateAddress.publicKey }
]
}
}],
},
plugins: [{
authorities: [
{ __kind: "Owner" },
{ __kind: "Pubkey", address: delegateAddress.publicKey }
],
plugin: {
__kind: 'Transfer',
fields: [{}],
},
}],
});

// await delegate(umi, {
// assetAddress: assetAddress.publicKey,
// owner: umi.identity,
// delegate: delegateAddress.publicKey
// }).sendAndConfirm(umi);

// await transfer(umi, {
// assetAddress: assetAddress.publicKey,
// newOwner: newOwner.publicKey,
// authority: delegateAddress,
// compressionProof: null
// }).sendAndConfirm(umi);

// const afterAsset = await fetchAsset(umi, assetAddress.publicKey);
// // console.log("Account State:", afterAsset);
// t.like(afterAsset, <Asset>{
// publicKey: assetAddress.publicKey,
// updateAuthority: umi.identity.publicKey,
// owner: newOwner.publicKey,
// name: 'Test Bread',
// uri: 'https://example.com/bread',
// });
});

});
36 changes: 36 additions & 0 deletions clients/rust/src/generated/accounts/hashed_asset_schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! This code was AUTOGENERATED using the kinobi library.
//! Please DO NOT EDIT THIS FILE, instead use visitors
//! to add features, then rerun kinobi to update it.
//!
//! [https://github.com/metaplex-foundation/kinobi]
//!
use crate::generated::types::PluginHash;
use borsh::BorshDeserialize;
use borsh::BorshSerialize;

#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct HashedAssetSchema {
pub asset_hash: [u8; 32],
pub plugin_hashes: Vec<PluginHash>,
}

impl HashedAssetSchema {
#[inline(always)]
pub fn from_bytes(data: &[u8]) -> Result<Self, std::io::Error> {
let mut data = data;
Self::deserialize(&mut data)
}
}

impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for HashedAssetSchema {
type Error = std::io::Error;

fn try_from(
account_info: &solana_program::account_info::AccountInfo<'a>,
) -> Result<Self, Self::Error> {
let mut data: &[u8] = &(*account_info.data).borrow();
Self::deserialize(&mut data)
}
}
2 changes: 2 additions & 0 deletions clients/rust/src/generated/accounts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
pub(crate) mod asset;
pub(crate) mod hashed_asset;
pub(crate) mod hashed_asset_schema;
pub(crate) mod plugin_header;
pub(crate) mod plugin_registry;

pub use self::asset::*;
pub use self::hashed_asset::*;
pub use self::hashed_asset_schema::*;
pub use self::plugin_header::*;
pub use self::plugin_registry::*;
Loading

0 comments on commit e19d598

Please sign in to comment.