From 073529118ce87f369cb3550e4e522a53be1abbca Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Sun, 29 Oct 2023 21:17:00 +0100 Subject: [PATCH 1/3] Nodejs: Anchor related changes --- bindings/nodejs/lib/types/block/address.ts | 29 ++++++- bindings/nodejs/lib/types/block/id.ts | 5 ++ .../nodejs/lib/types/block/output/output.ts | 80 +++++++++++++++++-- .../payload/signed_transaction/unlock.ts | 27 +++++++ 4 files changed, 135 insertions(+), 6 deletions(-) diff --git a/bindings/nodejs/lib/types/block/address.ts b/bindings/nodejs/lib/types/block/address.ts index 1e6420e265..14e1308a86 100644 --- a/bindings/nodejs/lib/types/block/address.ts +++ b/bindings/nodejs/lib/types/block/address.ts @@ -3,7 +3,7 @@ import { plainToInstance, Type } from 'class-transformer'; import { HexEncodedString } from '../utils'; -import { AccountId, NftId } from './id'; +import { AccountId, AnchorId, NftId } from './id'; /** * An address prepended by its network type. @@ -22,6 +22,8 @@ enum AddressType { Nft = 16, /** An implicit account creation address. */ ImplicitAccountCreation = 24, + /** An Anchor address. */ + Anchor = 28, /** An address with restricted capabilities. */ Restricted = 40, } @@ -65,6 +67,8 @@ abstract class Address { ImplicitAccountCreationAddress, data, ) as any as ImplicitAccountCreationAddress; + } else if (data.type == AddressType.Anchor) { + return plainToInstance(AnchorAddress, data) as any as AnchorAddress; } else if (data.type == AddressType.Restricted) { return plainToInstance( RestrictedAddress, @@ -160,6 +164,27 @@ class ImplicitAccountCreationAddress extends Address { } } +/** + * An Anchor address. + */ +class AnchorAddress extends Address { + /** + * The anchor ID. + */ + readonly anchorId: AnchorId; + /** + * @param address An anchor address as anchor ID. + */ + constructor(address: AnchorId) { + super(AddressType.Anchor); + this.anchorId = address; + } + + toString(): string { + return this.anchorId; + } +} + const RestrictedAddressDiscriminator = { property: 'type', subTypes: [ @@ -234,6 +259,7 @@ const AddressDiscriminator = { value: ImplicitAccountCreationAddress, name: AddressType.ImplicitAccountCreation as any, }, + { value: AnchorAddress, name: AddressType.Anchor as any }, { value: RestrictedAddress, name: AddressType.Restricted as any }, ], }; @@ -246,4 +272,5 @@ export { Ed25519Address, AccountAddress, NftAddress, + AnchorAddress, }; diff --git a/bindings/nodejs/lib/types/block/id.ts b/bindings/nodejs/lib/types/block/id.ts index 33adab1d9e..3267996d9d 100644 --- a/bindings/nodejs/lib/types/block/id.ts +++ b/bindings/nodejs/lib/types/block/id.ts @@ -8,6 +8,11 @@ import { HexEncodedString } from '../utils'; */ export type AccountId = HexEncodedString; +/** + * An Anchor ID represented as hex-encoded string. + */ +export type AnchorId = HexEncodedString; + /** * An NFT ID represented as hex-encoded string. */ diff --git a/bindings/nodejs/lib/types/block/output/output.ts b/bindings/nodejs/lib/types/block/output/output.ts index f7d1b11b03..f793df5b89 100644 --- a/bindings/nodejs/lib/types/block/output/output.ts +++ b/bindings/nodejs/lib/types/block/output/output.ts @@ -12,7 +12,7 @@ import { plainToInstance, Type } from 'class-transformer'; import { HexEncodedString, hexToBigInt, NumericString, u64 } from '../../utils'; import { TokenScheme, TokenSchemeDiscriminator } from './token-scheme'; import { INativeToken } from '../../models'; -import { AccountId, DelegationId } from '../id'; +import { AccountId, NftId, AnchorId, DelegationId } from '../id'; import { EpochIndex } from '../../block/slot'; export type OutputId = HexEncodedString; @@ -31,6 +31,8 @@ enum OutputType { Nft = 3, /** A Delegation output. */ Delegation = 4, + /** An Anchor output. */ + Anchor = 5, } /** @@ -76,6 +78,13 @@ abstract class Output { return plainToInstance(FoundryOutput, data) as any as FoundryOutput; } else if (data.type == OutputType.Nft) { return plainToInstance(NftOutput, data) as any as NftOutput; + } else if (data.type == OutputType.Delegation) { + return plainToInstance( + DelegationOutput, + data, + ) as any as DelegationOutput; + } else if (data.type == OutputType.Anchor) { + return plainToInstance(AnchorOutput, data) as any as AnchorOutput; } throw new Error('Invalid JSON'); } @@ -185,7 +194,7 @@ class AccountOutput extends ImmutableFeaturesOutput { * Unique identifier of the account, which is the BLAKE2b-256 hash of the Output ID that created it. * Unless its a newly created account, then the id is zeroed. */ - readonly accountId: HexEncodedString; + readonly accountId: AccountId; /** * A counter that denotes the number of foundries created by this account output. */ @@ -205,7 +214,7 @@ class AccountOutput extends ImmutableFeaturesOutput { constructor( amount: u64, mana: u64, - accountId: HexEncodedString, + accountId: AccountId, foundryCounter: number, unlockConditions: UnlockCondition[], ) { @@ -215,6 +224,66 @@ class AccountOutput extends ImmutableFeaturesOutput { this.mana = mana; } } + +/** + * Base class for state metadata outputs. + */ +abstract class StateMetadataOutput extends ImmutableFeaturesOutput { + readonly stateMetadata?: HexEncodedString; + + /** + * @param type The type of output. + * @param amount The amount of the output. + * @param unlockConditions The unlock conditions for the output. + */ + constructor( + type: OutputType, + amount: u64, + unlockConditions: UnlockCondition[], + ) { + super(type, amount, unlockConditions); + } +} + +/** + * An Anchor output. + */ +class AnchorOutput extends StateMetadataOutput { + /** + * Unique identifier of the anchor, which is the BLAKE2b-256 hash of the Output ID that created it. + * Unless its a newly created anchor, then the id is zeroed. + */ + readonly anchorId: AnchorId; + /** + * A counter that must increase by 1 every time the account output is state transitioned. + */ + readonly stateIndex: number; + /** + * The amount of (stored) Mana held by the output. + */ + readonly mana: u64; + + /** + * @param amount The amount of the output. + * @param mana The amount of stored mana. + * @param anchorId The anchor ID as hex-encoded string. + * @param stateIndex A counter that must increase by 1 every time the account output is state transitioned. + * @param unlockConditions The unlock conditions of the output. + */ + constructor( + amount: u64, + mana: u64, + anchorId: AnchorId, + stateIndex: number, + unlockConditions: UnlockCondition[], + ) { + super(OutputType.Account, amount, unlockConditions); + this.anchorId = anchorId; + this.stateIndex = stateIndex; + this.mana = mana; + } +} + /** * An NFT output. */ @@ -223,7 +292,7 @@ class NftOutput extends ImmutableFeaturesOutput { * Unique identifier of the NFT, which is the BLAKE2b-256 hash of the Output ID that created it. * Unless its newly minted, then the id is zeroed. */ - readonly nftId: HexEncodedString; + readonly nftId: NftId; /** * The amount of (stored) Mana held by the output. @@ -239,7 +308,7 @@ class NftOutput extends ImmutableFeaturesOutput { constructor( amount: u64, mana: u64, - nftId: HexEncodedString, + nftId: NftId, unlockConditions: UnlockCondition[], ) { super(OutputType.Nft, amount, unlockConditions); @@ -359,6 +428,7 @@ export { CommonOutput, BasicOutput, AccountOutput, + AnchorOutput, NftOutput, FoundryOutput, DelegationOutput, diff --git a/bindings/nodejs/lib/types/block/payload/signed_transaction/unlock.ts b/bindings/nodejs/lib/types/block/payload/signed_transaction/unlock.ts index 339027c761..0df204647d 100644 --- a/bindings/nodejs/lib/types/block/payload/signed_transaction/unlock.ts +++ b/bindings/nodejs/lib/types/block/payload/signed_transaction/unlock.ts @@ -24,6 +24,10 @@ enum UnlockType { * An NFT unlock. */ Nft = 3, + /** + * An Anchor unlock. + */ + Anchor = 4, } /** @@ -117,6 +121,24 @@ class NftUnlock extends Unlock { } } +/** + * An unlock which must reference a previous unlock which unlocks the anchor that the input is locked to. + */ +class AnchorUnlock extends Unlock { + /** + * The reference. + */ + readonly reference: number; + + /** + * @param reference An index referencing a previous unlock. + */ + constructor(reference: number) { + super(UnlockType.Anchor); + this.reference = reference; + } +} + const UnlockDiscriminator = { property: 'type', subTypes: [ @@ -136,6 +158,10 @@ const UnlockDiscriminator = { value: NftUnlock, name: UnlockType.Nft as any, }, + { + value: AnchorUnlock, + name: UnlockType.Anchor as any, + }, ], }; @@ -146,5 +172,6 @@ export { ReferenceUnlock, AccountUnlock, NftUnlock, + AnchorUnlock, UnlockDiscriminator, }; From 0d38de240230789113ff36578d34b9e19863bbf2 Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Sun, 29 Oct 2023 21:21:17 +0100 Subject: [PATCH 2/3] Nit --- bindings/nodejs/lib/types/block/output/output.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/nodejs/lib/types/block/output/output.ts b/bindings/nodejs/lib/types/block/output/output.ts index f793df5b89..e85f39140c 100644 --- a/bindings/nodejs/lib/types/block/output/output.ts +++ b/bindings/nodejs/lib/types/block/output/output.ts @@ -255,7 +255,7 @@ class AnchorOutput extends StateMetadataOutput { */ readonly anchorId: AnchorId; /** - * A counter that must increase by 1 every time the account output is state transitioned. + * A counter that must increase by 1 every time the anchor output is state transitioned. */ readonly stateIndex: number; /** @@ -267,7 +267,7 @@ class AnchorOutput extends StateMetadataOutput { * @param amount The amount of the output. * @param mana The amount of stored mana. * @param anchorId The anchor ID as hex-encoded string. - * @param stateIndex A counter that must increase by 1 every time the account output is state transitioned. + * @param stateIndex A counter that must increase by 1 every time the anchor output is state transitioned. * @param unlockConditions The unlock conditions of the output. */ constructor( From 844432815f3231407eb8defcbe45aa9e73a4eeee Mon Sep 17 00:00:00 2001 From: Thibault Martinez Date: Mon, 30 Oct 2023 10:50:56 +0100 Subject: [PATCH 3/3] Remove StateMetadataOutput --- .../nodejs/lib/types/block/output/output.ts | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/bindings/nodejs/lib/types/block/output/output.ts b/bindings/nodejs/lib/types/block/output/output.ts index e85f39140c..95bfdd45af 100644 --- a/bindings/nodejs/lib/types/block/output/output.ts +++ b/bindings/nodejs/lib/types/block/output/output.ts @@ -225,30 +225,10 @@ class AccountOutput extends ImmutableFeaturesOutput { } } -/** - * Base class for state metadata outputs. - */ -abstract class StateMetadataOutput extends ImmutableFeaturesOutput { - readonly stateMetadata?: HexEncodedString; - - /** - * @param type The type of output. - * @param amount The amount of the output. - * @param unlockConditions The unlock conditions for the output. - */ - constructor( - type: OutputType, - amount: u64, - unlockConditions: UnlockCondition[], - ) { - super(type, amount, unlockConditions); - } -} - /** * An Anchor output. */ -class AnchorOutput extends StateMetadataOutput { +class AnchorOutput extends ImmutableFeaturesOutput { /** * Unique identifier of the anchor, which is the BLAKE2b-256 hash of the Output ID that created it. * Unless its a newly created anchor, then the id is zeroed. @@ -262,6 +242,10 @@ class AnchorOutput extends StateMetadataOutput { * The amount of (stored) Mana held by the output. */ readonly mana: u64; + /** + * Metadata that can only be changed by the state controller. + */ + readonly stateMetadata?: HexEncodedString; /** * @param amount The amount of the output. @@ -269,6 +253,7 @@ class AnchorOutput extends StateMetadataOutput { * @param anchorId The anchor ID as hex-encoded string. * @param stateIndex A counter that must increase by 1 every time the anchor output is state transitioned. * @param unlockConditions The unlock conditions of the output. + * @param stateMetadata Metadata that can only be changed by the state controller. */ constructor( amount: u64, @@ -276,11 +261,13 @@ class AnchorOutput extends StateMetadataOutput { anchorId: AnchorId, stateIndex: number, unlockConditions: UnlockCondition[], + stateMetadata?: HexEncodedString, ) { super(OutputType.Account, amount, unlockConditions); this.anchorId = anchorId; this.stateIndex = stateIndex; this.mana = mana; + this.stateMetadata = stateMetadata; } }