Skip to main content
added 145 characters in body
Source Link
Serban
  • 1.5k
  • 3
  • 9

If [u8; 16] works for you, then you can trick Anchor into treating it as a u128 by creating a custom type with the same name, "u128". To not pollute the outer scope, you declare it in a module. Like so:

mod custom_scope {

    use anchor_lang::prelude::*;

    #[derive(Copy, Clone, bytemuck::Zeroable, bytemuck::Pod, Debug)]
    #[repr(C)]
    pub struct u128(pub [u8; 16]);

    impl u128 {
        pub fn as_u128(&self) -> core::primitive::u128 {
            core::primitive::u128::from_le_bytes(self.0)
        }
    }

    #[account(zero_copy)]
    #[repr(C)]
    pub struct SomeStruct {
        pub authority: Pubkey,
        pub some_value: u128, // anchor will think this `u128` is a primitive and not a custom type
        pub data: u64,
    }
}

It is key to also declare SomeStruct in the same scope so that we can do pub some_value: u128 because this is what tricks Anchor into treating it as a regular u128 and not a custom type.

And now, when your client sends data as u128 you can simply casttransform it into the type the account expects, with custom_scope::u128(some_value.to_le_bytes()).

Or if you want your my_account.some_value to act as a u128, you can simply do my_account.some_value.as_u128().

Here's the demo: https://beta.solpg.io/65184223fb53fa325bfd0bc9

Check the test file and notice it treats the someValue field in the account as BN without additional conversion. This works because in the account, the byte layout of custom_scope::u128 and u128 is the same so the client can treat it as a simple u128.

And in the IDL that the above link generates during build, it will show

{
    "name": "someValue",
    "type": "u128"
}

If [u8; 16] works for you, then you can trick Anchor into treating it as a u128 by creating a custom type with the same name, "u128". To not pollute the outer scope, you declare it in a module. Like so:

mod custom_scope {

    use anchor_lang::prelude::*;

    #[derive(Copy, Clone, bytemuck::Zeroable, bytemuck::Pod, Debug)]
    #[repr(C)]
    pub struct u128(pub [u8; 16]);

    impl u128 {
        pub fn as_u128(&self) -> core::primitive::u128 {
            core::primitive::u128::from_le_bytes(self.0)
        }
    }

    #[account(zero_copy)]
    #[repr(C)]
    pub struct SomeStruct {
        pub authority: Pubkey,
        pub some_value: u128, // anchor will think this `u128` is a primitive and not a custom type
        pub data: u64,
    }
}

It is key to also declare SomeStruct in the same scope so that we can do pub some_value: u128 because this is what tricks Anchor into treating it as a regular u128 and not a custom type.

And now, when your client sends data as u128 you can simply cast it into the type the account expects, with custom_scope::u128(some_value.to_le_bytes()).

Or if you want your my_account.some_value to act as a u128, you can simply do my_account.some_value.as_u128().

Here's the demo: https://beta.solpg.io/65184223fb53fa325bfd0bc9

Check the test file and notice it treats the someValue field in the account as BN without additional conversion.

And in the IDL that the above link generates during build, it will show

{
    "name": "someValue",
    "type": "u128"
}

If [u8; 16] works for you, then you can trick Anchor into treating it as a u128 by creating a custom type with the same name, "u128". To not pollute the outer scope, you declare it in a module. Like so:

mod custom_scope {

    use anchor_lang::prelude::*;

    #[derive(Copy, Clone, bytemuck::Zeroable, bytemuck::Pod, Debug)]
    #[repr(C)]
    pub struct u128(pub [u8; 16]);

    impl u128 {
        pub fn as_u128(&self) -> core::primitive::u128 {
            core::primitive::u128::from_le_bytes(self.0)
        }
    }

    #[account(zero_copy)]
    #[repr(C)]
    pub struct SomeStruct {
        pub authority: Pubkey,
        pub some_value: u128, // anchor will think this `u128` is a primitive and not a custom type
        pub data: u64,
    }
}

It is key to also declare SomeStruct in the same scope so that we can do pub some_value: u128 because this is what tricks Anchor into treating it as a regular u128 and not a custom type.

And now, when your client sends data as u128 you can simply transform it into the type the account expects, with custom_scope::u128(some_value.to_le_bytes()).

Or if you want your my_account.some_value to act as a u128, you can simply do my_account.some_value.as_u128().

Here's the demo: https://beta.solpg.io/65184223fb53fa325bfd0bc9

Check the test file and notice it treats the someValue field in the account as BN without additional conversion. This works because in the account, the byte layout of custom_scope::u128 and u128 is the same so the client can treat it as a simple u128.

And in the IDL that the above link generates during build, it will show

{
    "name": "someValue",
    "type": "u128"
}
Source Link
Serban
  • 1.5k
  • 3
  • 9

If [u8; 16] works for you, then you can trick Anchor into treating it as a u128 by creating a custom type with the same name, "u128". To not pollute the outer scope, you declare it in a module. Like so:

mod custom_scope {

    use anchor_lang::prelude::*;

    #[derive(Copy, Clone, bytemuck::Zeroable, bytemuck::Pod, Debug)]
    #[repr(C)]
    pub struct u128(pub [u8; 16]);

    impl u128 {
        pub fn as_u128(&self) -> core::primitive::u128 {
            core::primitive::u128::from_le_bytes(self.0)
        }
    }

    #[account(zero_copy)]
    #[repr(C)]
    pub struct SomeStruct {
        pub authority: Pubkey,
        pub some_value: u128, // anchor will think this `u128` is a primitive and not a custom type
        pub data: u64,
    }
}

It is key to also declare SomeStruct in the same scope so that we can do pub some_value: u128 because this is what tricks Anchor into treating it as a regular u128 and not a custom type.

And now, when your client sends data as u128 you can simply cast it into the type the account expects, with custom_scope::u128(some_value.to_le_bytes()).

Or if you want your my_account.some_value to act as a u128, you can simply do my_account.some_value.as_u128().

Here's the demo: https://beta.solpg.io/65184223fb53fa325bfd0bc9

Check the test file and notice it treats the someValue field in the account as BN without additional conversion.

And in the IDL that the above link generates during build, it will show

{
    "name": "someValue",
    "type": "u128"
}