Skip to content

Commit

Permalink
Merge branch 'main' into add-idl-to-elf
Browse files Browse the repository at this point in the history
  • Loading branch information
ngundotra authored Jun 14, 2024
2 parents 21dba99 + 4560c20 commit f0f7f4f
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions clients/js/proxy/test/_setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ export const STUB_KEY = Uint8Array.from([
198, 193, 21, 158, 198, 203, 241, 229, 179, 162, 229, 129, 109, 151, 51, 135,
240, 128, 114, 242, 103, 170, 154, 47, 218, 130, 218, 139, 45, 47,
]);

export function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
18 changes: 17 additions & 1 deletion clients/js/proxy/test/transfer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ import {
ExtensionType,
Standard,
State,
Type,
fetchAsset,
getExtension,
getProperty,
transfer,
} from '@nifty-oss/asset';
import { Keypair } from '@solana/web3.js';
import test from 'ava';
import { create } from '../src';
import { findProxiedAssetPda } from '../src/pda';
import { STUB_KEY, createUmi } from './_setup';
import { STUB_KEY, createUmi, sleep } from './_setup';

test('it cannot transfer a non-signer proxied asset', async (t) => {
// Given a Umi instance and a new signer.
Expand Down Expand Up @@ -114,6 +116,12 @@ test('it can execute custom logic on transfer', async (t) => {
const initial = attributes?.values[0].value;
t.true(parseInt(initial!) === 0);

// initial value for the last transferred timestamp
const timestamp = getProperty(asset, 'last_transferred', Type.Number)!.value;

// We wait for a second to ensure the timestamp is different.
await sleep(1000);

const recipient = generateSigner(umi).publicKey;
const proxy = getExtension(asset, ExtensionType.Proxy);
// And we transfer the proxied asset through the proxy program (using
Expand All @@ -139,6 +147,14 @@ test('it can execute custom logic on transfer', async (t) => {
const current = parseInt(attributes?.values[0].value!);
t.true(current === 1);
t.assert(parseInt(initial!) < current);

// And the last transferred timestamp is updated.
const lastTransferred = getProperty(
asset,
'last_transferred',
Type.Number
)!.value;
t.assert(timestamp < lastTransferred);
});

test('it can transfer the proxy asset multiple times', async (t) => {
Expand Down
2 changes: 1 addition & 1 deletion idls/asset_program.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.6.0",
"version": "0.6.1",
"name": "asset_program",
"instructions": [
{
Expand Down
2 changes: 1 addition & 1 deletion programs/asset/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "asset-program"
version = "0.6.0"
version = "0.6.1"
authors = ["nifty-oss maintainers <[email protected]>"]
edition = "2021"
readme = "./README.md"
Expand Down
21 changes: 19 additions & 2 deletions programs/asset/types/src/extensions/grouping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ use crate::{error::Error, state::NullablePubkey};

use super::{ExtensionBuilder, ExtensionData, ExtensionDataMut, ExtensionType, Lifecycle};

/// Empty string used for backwards compatibility with metadata extension.
const EMPTY: [u8; 32] = [0u8; 32];

/// Extension to define a group of assets.
///
/// Assets that are intented to be use as group "markers" must have this extension
Expand All @@ -36,10 +39,17 @@ impl<'a> ExtensionData<'a> for Grouping<'a> {
fn from_bytes(bytes: &'a [u8]) -> Self {
let (size, rest) = bytes.split_at(std::mem::size_of::<u64>());
let (max_size, delegate) = rest.split_at(std::mem::size_of::<u64>());

Self {
size: bytemuck::from_bytes(size),
max_size: bytemuck::from_bytes(max_size),
delegate: bytemuck::from_bytes(delegate),
// backwards compatibility for grouping extension: if there are not enough
// bytes to read the delegate, we assume it is empty
delegate: bytemuck::from_bytes(if delegate.len() < EMPTY.len() {
&EMPTY
} else {
delegate
}),
}
}

Expand Down Expand Up @@ -72,10 +82,17 @@ impl<'a> ExtensionDataMut<'a> for GroupingMut<'a> {
fn from_bytes_mut(bytes: &'a mut [u8]) -> Self {
let (size, rest) = bytes.split_at_mut(std::mem::size_of::<u64>());
let (max_size, delegate) = rest.split_at_mut(std::mem::size_of::<u64>());

Self {
size: bytemuck::from_bytes_mut(size),
max_size: bytemuck::from_bytes_mut(max_size),
delegate: bytemuck::from_bytes_mut(delegate),
// backwards compatibility for grouping extension: if there are not enough
// bytes to read the delegate, we assume it is empty
delegate: bytemuck::from_bytes_mut(if delegate.len() < EMPTY.len() {
unsafe { (&EMPTY as *const [u8] as *mut [u8]).as_mut().unwrap() }
} else {
delegate
}),
}
}
}
Expand Down
20 changes: 17 additions & 3 deletions programs/proxy/src/processor/create.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
use nifty_asset_interface::{
extensions::{AttributesBuilder, BlobBuilder, ExtensionBuilder, ProxyBuilder},
extensions::{
AttributesBuilder, BlobBuilder, ExtensionBuilder, PropertiesBuilder, ProxyBuilder,
},
instructions::CreateCpiBuilder,
types::ExtensionInput,
ExtensionType, Standard,
};
use solana_program::{entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey};
use solana_program::{
clock::Clock, entrypoint::ProgramResult, program_error::ProgramError, pubkey::Pubkey,
sysvar::Sysvar,
};

use crate::{
instruction::{
Expand Down Expand Up @@ -86,6 +91,15 @@ pub fn process_create(
data: Some(data),
};

let data = PropertiesBuilder::with_capacity(30)
.add_number("last_transferred", Clock::get()?.unix_timestamp as u64)
.data();
let properties = ExtensionInput {
extension_type: ExtensionType::Properties,
length: data.len() as u32,
data: Some(data),
};

// creates the proxied asset

CreateCpiBuilder::new(ctx.accounts.nifty_asset_program)
Expand All @@ -97,6 +111,6 @@ pub fn process_create(
.system_program(ctx.accounts.system_program)
.name(metadata.name)
.standard(Standard::Proxied)
.extensions(vec![attributes, blob, proxy])
.extensions(vec![attributes, blob, proxy, properties])
.invoke_signed(&[&signer])
}
18 changes: 17 additions & 1 deletion programs/proxy/src/processor/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use nifty_asset_interface::{
accounts::TransferAccounts,
extensions::{Attributes, AttributesBuilder, BlobBuilder, ExtensionBuilder},
extensions::{Attributes, AttributesBuilder, BlobBuilder, ExtensionBuilder, PropertiesBuilder},
fetch_proxy_data,
instructions::{TransferCpiBuilder, UpdateCpiBuilder},
state::Asset,
Expand Down Expand Up @@ -93,6 +93,22 @@ pub fn process_transfer<'a>(
})
.invoke_signed(&[&signer])?;

// updates the properties (last tranferred)

let data = PropertiesBuilder::with_capacity(30)
.add_number("last_transferred", Clock::get()?.unix_timestamp as u64)
.data();

UpdateCpiBuilder::new(nifty_asset_program)
.asset(ctx.accounts.asset)
.authority(ctx.accounts.asset)
.extension(ExtensionInput {
extension_type: ExtensionType::Properties,
length: data.len() as u32,
data: Some(data),
})
.invoke_signed(&[&signer])?;

// cpi into the Nifty Asset program to perform the transfer

TransferCpiBuilder::new(nifty_asset_program)
Expand Down

0 comments on commit f0f7f4f

Please sign in to comment.