Skip to content

Commit

Permalink
[TX] AddressStateTx
Browse files Browse the repository at this point in the history
  • Loading branch information
peak3d committed Jan 12, 2023
1 parent f0a5bee commit bdf0ead
Show file tree
Hide file tree
Showing 5 changed files with 375 additions and 1 deletion.
63 changes: 63 additions & 0 deletions examples/platformvm/buildAddressStateTx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Avalanche, Buffer } from "@c4tplatform/caminojs/dist"
import {
PlatformVMAPI,
KeyChain,
UnsignedTx,
Tx
} from "@c4tplatform/caminojs/dist/apis/platformvm"
import { ExamplesConfig } from "../common/examplesConfig"

const config: ExamplesConfig = require("../common/examplesConfig.json")
const avalanche: Avalanche = new Avalanche(
config.host,
config.port,
config.protocol,
config.networkID
)

/**
* @ignore
*/
let privKey: string =
"PrivateKey-vmRQiZeXEXYMyJhEiqdC2z5JhuDbxL8ix9UVvjgMu2Er1NepE"

let pchain: PlatformVMAPI
let pKeychain: KeyChain
let pAddressStrings: string[]

const InitAvalanche = async () => {
await avalanche.fetchNetworkSettings()
pchain = avalanche.PChain()
pKeychain = pchain.keyChain()
// P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u9xde7p
pKeychain.importKey(privKey)

pAddressStrings = pchain.keyChain().getAddressStrings()
}

const main = async (): Promise<any> => {
await InitAvalanche()

const address = pAddressStrings[0]
const state = 1 // AddressStateRoleKyc
const remove = false
const memo: Buffer = Buffer.from(
"Utility function to create an AddressStateTx transaction"
)

const unsignedTx: UnsignedTx = await pchain.buildAddressStateTx(
undefined,
pAddressStrings,
pAddressStrings,
address,
state,
remove,
memo
)

const tx: Tx = unsignedTx.sign(pKeychain)
const txid: string = await pchain.issueTx(tx)
console.log(`Success! TXID: ${txid}`)
}

main()
167 changes: 167 additions & 0 deletions src/apis/platformvm/addressstatetx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/**
* @packageDocumentation
* @module API-PlatformVM-AddressStateTx
*/
import { Buffer } from "buffer/"
import BinTools from "../../utils/bintools"
import { PlatformVMConstants } from "./constants"
import { TransferableOutput } from "./outputs"
import { TransferableInput } from "./inputs"
import { BaseTx } from "./basetx"
import { DefaultNetworkID } from "../../utils/constants"
import { Serialization, SerializedEncoding } from "../../utils/serialization"

/**
* @ignore
*/
const bintools: BinTools = BinTools.getInstance()
const serialization: Serialization = Serialization.getInstance()

/**
* Class representing an unsigned AdressStateTx transaction.
*/
export class AddressStateTx extends BaseTx {
protected _typeName = "AddressStateTx"
protected _typeID = PlatformVMConstants.ADDRESSSTATETX

serialize(encoding: SerializedEncoding = "hex"): object {
let fields: object = super.serialize(encoding)
return {
...fields,
address: serialization.encoder(this.address, encoding, "Buffer", "cb58"),
state: this.state,
remove: this.remove
}
}
deserialize(fields: object, encoding: SerializedEncoding = "hex") {
super.deserialize(fields, encoding)
this.address = serialization.decoder(
fields["address"],
encoding,
"cb58",
"Buffer",
20
)
this.state = fields["state"]
this.remove = fields["remove"]
}

// The address to add / remove state
protected address = Buffer.alloc(20)
// The state to set / unset
protected state = 0
// Remove or add the flag ?
protected remove: boolean

/**
* Returns the id of the [[AddressStateTx]]
*/
getTxType(): number {
return this._typeID
}

/**
* Returns the address
*/
getAddress(): Buffer {
return this.address
}

/**
* Returns the state
*/
getState(): Number {
return this.state
}

/**
* Returns the remove flag
*/
getRemove(): boolean {
return this.remove
}

/**
* Takes a {@link https://github.com/feross/buffer|Buffer} containing an [[AddressStateTx]], parses it, populates the class, and returns the length of the [[AddressStateTx]] in bytes.
*
* @param bytes A {@link https://github.com/feross/buffer|Buffer} containing a raw [[AddressStateTx]]
*
* @returns The length of the raw [[AddressStateTx]]
*
* @remarks assume not-checksummed
*/
fromBuffer(bytes: Buffer, offset: number = 0): number {
offset = super.fromBuffer(bytes, offset)
this.address = bintools.copyFrom(bytes, offset, offset + 20)
offset += 20
this.state = bintools.copyFrom(bytes, offset, offset + 1)[0]
offset += 1
this.remove = bintools.copyFrom(bytes, offset, offset + 1)[0] != 0
offset += 1
return offset
}

/**
* Returns a {@link https://github.com/feross/buffer|Buffer} representation of the [[AddressStateTx]].
*/
toBuffer(): Buffer {
const superbuff: Buffer = super.toBuffer()

let bsize: number = superbuff.length + this.address.length + 2
const barr: Buffer[] = [
superbuff,
this.address,
Buffer.from([this.state]),
Buffer.from([this.remove ? 1 : 0])
]
return Buffer.concat(barr, bsize)
}

clone(): this {
const newAddressStateTx: AddressStateTx = new AddressStateTx()
newAddressStateTx.fromBuffer(this.toBuffer())
return newAddressStateTx as this
}

create(...args: any[]): this {
return new AddressStateTx(...args) as this
}

/**
* Class representing an unsigned RegisterNode transaction.
*
* @param networkID Optional networkID, [[DefaultNetworkID]]
* @param blockchainID Optional blockchainID, default Buffer.alloc(32, 16)
* @param outs Optional array of the [[TransferableOutput]]s
* @param ins Optional array of the [[TransferableInput]]s
* @param memo Optional {@link https://github.com/feross/buffer|Buffer} for the memo field
* @param address Optional address to alter state.
* @param state Optional state to alter.
* @param remove Optional if true remove the flag, otherwise set
*/
constructor(
networkID: number = DefaultNetworkID,
blockchainID: Buffer = Buffer.alloc(32, 16),
outs: TransferableOutput[] = undefined,
ins: TransferableInput[] = undefined,
memo: Buffer = undefined,
address: string | Buffer = undefined,
state: number = undefined,
remove: boolean = undefined
) {
super(networkID, blockchainID, outs, ins, memo)
if (typeof address != "undefined") {
if (typeof address === "string") {
this.address = bintools.stringToAddress(address)
} else {
this.address = address
}
}
if (typeof state != "undefined") {
this.state = state
}
if (typeof remove != "undefined") {
this.remove = remove
}
}
}
69 changes: 69 additions & 0 deletions src/apis/platformvm/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,75 @@ export class PlatformVMAPI extends JRPCAPI {

return builtUnsignedTx
}
/**
* Build an unsigned [[AddressStateTx]].
*
* @param utxoset A set of UTXOs that the transaction is built on
* @param fromAddresses The addresses being used to send the funds from the UTXOs {@link https://github.com/feross/buffer|Buffer}
* @param changeAddresses The addresses that can spend the change remaining from the spent UTXOs.
* @param address The address to alter state.
* @param state The state to set or remove on the given address
* @param remove Optional. Flag if state should be applied or removed
* @param memo Optional contains arbitrary bytes, up to 256 bytes
* @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN}
* @param changeThreshold Optional. The number of signatures required to spend the funds in the resultant change UTXO
*
* @returns An unsigned AddressStateTx created from the passed in parameters.
*/
buildAddressStateTx = async (
utxoset: UTXOSet,
fromAddresses: string[],
changeAddresses: string[],
address: string | Buffer,
state: number,
remove: boolean = false,
memo: Buffer = undefined,
asOf: BN = ZeroBN,
changeThreshold: number = 1
): Promise<UnsignedTx> => {
const from: Buffer[] = this._cleanAddressArray(
fromAddresses,
"buildRegisterNodeTx"
).map((a: string): Buffer => bintools.stringToAddress(a))
const change: Buffer[] = this._cleanAddressArray(
changeAddresses,
"buildRegisterNodeTx"
).map((a: string): Buffer => bintools.stringToAddress(a))
const addressBuf =
typeof address === "string" ? this.parseAddress(address) : address
if (memo instanceof PayloadBase) {
memo = memo.getPayload()
}

const avaxAssetID: Buffer = await this.getAVAXAssetID()
const networkID: number = this.core.getNetworkID()
const blockchainID: Buffer = bintools.cb58Decode(this.blockchainID)
const fee: BN = this.getTxFee()

const builtUnsignedTx: UnsignedTx = await this._getBuilder(
utxoset
).buildAddressStateTx(
networkID,
blockchainID,
from,
change,
addressBuf,
state,
remove,
fee,
avaxAssetID,
memo,
asOf,
changeThreshold
)

if (!(await this.checkGooseEgg(builtUnsignedTx, this.getCreationTxFee()))) {
/* istanbul ignore next */
throw new GooseEggCheckError("Failed Goose Egg Check")
}

return builtUnsignedTx
}

/**
* Build an unsigned [[RegisterNodeTx]].
Expand Down
75 changes: 75 additions & 0 deletions src/apis/platformvm/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import {
} from "."
import { GenesisData } from "../avm"
import { DepositTx } from "./depositTx"
import { AddressStateTx } from "./addressstatetx"

export type LockMode = "Unlocked" | "Bond" | "Deposit" | "Stake"

Expand Down Expand Up @@ -1035,6 +1036,80 @@ export class Builder {
return new UnsignedTx(tx)
}

/**
* Build an unsigned [[AddressStateTx]].
*
* @param networkID Networkid, [[DefaultNetworkID]]
* @param blockchainID Blockchainid, default undefined
* @param fromAddresses The addresses being used to send the funds from the UTXOs {@link https://github.com/feross/buffer|Buffer}
* @param changeAddresses The addresses that can spend the change remaining from the spent UTXOs.
* @param address The address to alter state.
* @param state The state to set or remove on the given address
* @param remove Optional. Flag if state should be applied or removed
* @param fee Optional. The amount of fees to burn in its smallest denomination, represented as {@link https://github.com/indutny/bn.js/|BN}
* @param feeAssetID Optional. The assetID of the fees being burned
* @param memo Optional contains arbitrary bytes, up to 256 bytes
* @param asOf Optional. The timestamp to verify the transaction against as a {@link https://github.com/indutny/bn.js/|BN}
* @param changeThreshold Optional. The number of signatures required to spend the funds in the resultant change UTXO
*
* @returns An unsigned AddressStateTx created from the passed in parameters.
*/
buildAddressStateTx = async (
networkID: number = DefaultNetworkID,
blockchainID: Buffer,
fromAddresses: Buffer[],
changeAddresses: Buffer[],
address: Buffer,
state: number,
remove: boolean = false,
fee: BN = zero,
feeAssetID: Buffer = undefined,
memo: Buffer = undefined,
asOf: BN = zero,
changeThreshold: number = 1
): Promise<UnsignedTx> => {
let ins: TransferableInput[] = []
let outs: TransferableOutput[] = []

if (this._feeCheck(fee, feeAssetID)) {
const aad: AssetAmountDestination = new AssetAmountDestination(
[],
0,
fromAddresses,
changeAddresses,
changeThreshold
)

aad.addAssetAmount(feeAssetID, zero, fee)

const minSpendableErr: Error = await this.spender.getMinimumSpendable(
aad,
asOf,
zero,
"Unlocked"
)
if (typeof minSpendableErr === "undefined") {
ins = aad.getInputs()
outs = aad.getAllOutputs()
} else {
throw minSpendableErr
}
}

const addressStateTx: AddressStateTx = new AddressStateTx(
networkID,
blockchainID,
outs,
ins,
memo,
address,
state,
remove
)

return new UnsignedTx(addressStateTx)
}

/**
* Build an unsigned [[RegisterNodeTx]].
*
Expand Down
Loading

0 comments on commit bdf0ead

Please sign in to comment.