diff --git a/README.md b/README.md index 13f3e560..36061cc6 100644 --- a/README.md +++ b/README.md @@ -114,81 +114,40 @@ Example of how to construct a transaction and push it to the network: ```ts import { - Args, - CLValue, - CLValueOption, - CLValueUInt64, - CLValueUInt512, - Duration, HttpHandler, - InitiatorAddr, - KeyAlgorithm, - PricingMode, - PrivateKey, - PublicKey, RpcClient, - Timestamp, - TransactionEntryPoint, - TransactionScheduling, - TransactionTarget, - TransactionV1, - TransactionV1Payload, - TransactionEntryPointEnum, - PaymentLimitedMode + NativeTransferBuilder, + PrivateKey, + KeyAlgorithm, + PublicKey } from 'casper-js-sdk'; const rpcHandler = new HttpHandler('http://:7777/rpc'); const rpcClient = new RpcClient(rpcHandler); const privateKey = await PrivateKey.generate(KeyAlgorithm.ED25519); -const timestamp = new Timestamp(new Date()); -const paymentAmount = '20000000000000'; - -const pricingMode = new PricingMode(); -const paymentLimitedMode = new PaymentLimitedMode(); -paymentLimitedMode.gasPriceTolerance = 1; -paymentLimitedMode.paymentAmount = paymentAmount; -paymentLimitedMode.standardPayment = true; -pricingMode.paymentLimited = paymentLimitedMode; - -const args = Args.fromMap({ - target: CLValue.newCLPublicKey( + +const transaction = new NativeTransferBuilder() + .from(privateKey.publicKey) + .target( PublicKey.fromHex( '0202f5a92ab6da536e7b1a351406f3744224bec85d7acbab1497b65de48a1a707b64' ) - ), - amount: CLValueUInt512.newCLUInt512(paymentAmount), - id: CLValueOption.newCLOption(CLValueUInt64.newCLUint64(3)) // memo ( optional ) -}); + ) + .amount('25000000000') // Amount in motes + .id(Date.now()) + .chainName('casper-net-1') + .payment(100_000_000) + .build(); -const transactionTarget = new TransactionTarget({}); // Native target; -const entryPoint = new TransactionEntryPoint( - TransactionEntryPointEnum.Transfer -); -const scheduling = new TransactionScheduling({}); // Standard; - -const transactionPayload = TransactionV1Payload.build({ - initiatorAddr: new InitiatorAddr(privateKey.publicKey), - ttl: new Duration(1800000), - args, - timestamp, - entryPoint, - scheduling, - transactionTarget, - chainName: 'casper-net-1', - pricingMode -}); - -const transactionV1 = TransactionV1.makeTransactionV1( - transactionPayload -); -await transactionV1.sign(privateKey); +await transaction.sign(privateKey); -const tx = Transaction.fromTransactionV1(transactionV1); - -const result = await rpcClient.putTransaction(tx); - -console.log(`Transaction Hash: ${result.transactionHash}`); +try { + const result = await rpcClient.putTransaction(transaction); + console.log(`Transaction Hash: ${result.transactionHash}`); +} catch (e) { + console.error(e); +} ``` ### Creating a legacy deploy diff --git a/migration-guide-v2-v5.md b/migration-guide-v2-v5.md index 32f86522..956ff2ed 100644 --- a/migration-guide-v2-v5.md +++ b/migration-guide-v2-v5.md @@ -100,13 +100,14 @@ const nativeTarget = new TransactionTarget({}); const stored = new StoredTarget(); const invocationTarget = new TransactionInvocationTarget(); invocationTarget.byHash = new Hash(Uint8Array.from([])); // an example of hash -storedTarget.runtime = 'VmCasperV1'; // an example of runtime +storedTarget.runtime = TransactionRuntime.vmCasperV1(); // an example of runtime storedTarget.id = invocationTarget; const storedTransactionTarget = new TransactionTarget( undefined, stored ); + // OR const storedTransactionTarget1 = new TransactionTarget(); storedTransactionTarget1.stored = stored; @@ -117,16 +118,15 @@ storedTransactionTarget1.stored = stored; ```typescript const sessionTarget = new SessionTarget(); sessionTarget.moduleBytes = Uint8Array.from([]); // an example of module bytes -sessionTarget.runtime = 'VmCasperV1'; // an example of runtime -sessionTarget.transferredValue = 1000; // an example of transferredValue +sessionTarget.runtime = TransactionRuntime.vmCasperV1(); // an example of runtime sessionTarget.isInstallUpgrade = true; // an example of isInstallUpgrade -sessionTarget.seed = new Hash(Uint8Array.from([])); // an example of seed const sessionTransactionTarget = new TransactionTarget( undefined, undefined, sessionTarget ); + // OR const sessionTransactionTarget1 = new TransactionTarget(); sessionTransactionTarget1.session = sessionTarget; @@ -158,19 +158,20 @@ Specifies how transaction fees are calculated. Supports three modes: #### Examples: -- **FixedMode**: +- **PaymentLimitedMode**: ```typescript -const fixedMode = new FixedMode(); -fixedMode.gasPriceTolerance = 2; -fixedMode.additionalComputationFactor = 1; +const paymentLimited = new PaymentLimitedMode(); +paymentLimited.standardPayment = true; +paymentLimited.paymentAmount = '250000000'; +paymentLimited.gasPriceTolerance = 1; ``` - **Assign Pricing Mode**: ```typescript const pricingMode = new PricingMode(); -pricingMode.fixed = fixedMode; +pricingMode.paymentLimited = paymentLimited; ``` --- @@ -197,10 +198,10 @@ const publicKey = privateKey.publicKey; ```typescript const args = Args.fromMap({ - target: CLValue.newCLPublicKey( - PublicKey.fromHex('') - ), - amount: CLValueUInt512.newCLUInt512('2000000000') // 2 CSPR + target: CLValue.newCLPublicKey( + PublicKey.fromHex('') + ), + amount: CLValueUInt512.newCLUInt512('2000000000') // 2 CSPR }); ``` @@ -216,7 +217,7 @@ const transactionTarget = new TransactionTarget({}); // Native target; ```typescript const entryPoint = new TransactionEntryPoint( - TransactionEntryPointEnum.Transfer + TransactionEntryPointEnum.Transfer ); ``` @@ -242,19 +243,19 @@ pricingMode.paymentLimited = paymentLimitedMode; ```typescript const transactionPayload = TransactionV1Payload.build({ - initiatorAddr: new InitiatorAddr(publicKey), - ttl: new Duration(1800000), - args, - timestamp: new Timestamp(new Date()), - entryPoint, - scheduling, - transactionTarget, - chainName: 'casper-net-1', - pricingMode + initiatorAddr: new InitiatorAddr(publicKey), + ttl: new Duration(1800000), + args, + timestamp: new Timestamp(new Date()), + entryPoint, + scheduling, + transactionTarget, + chainName: 'casper-net-1', + pricingMode }); const transaction = TransactionV1.makeTransactionV1( - transactionPayload + transactionPayload ); await transaction.sign(privateKey); ``` @@ -265,3 +266,47 @@ await transaction.sign(privateKey); const result = await rpcClient.putTransactionV1(transaction); console.log(`Transaction Hash: ${result.transactionHash}`); ``` + +## Using [TransactionBuilder](./src/types/TransactionBuilder.md) + +The `TransactionBuilder` is a base class used to create various types of transactions. By extending this class, you can build custom transaction types with specific methods and properties. + +#### Example of how to construct a transaction with TransactionBuilder and push it to the network: + +```ts +import { + HttpHandler, + RpcClient, + NativeTransferBuilder, + PrivateKey, + KeyAlgorithm, + PublicKey +} from 'casper-js-sdk'; + +const rpcHandler = new HttpHandler('http://:7777/rpc'); +const rpcClient = new RpcClient(rpcHandler); + +const privateKey = await PrivateKey.generate(KeyAlgorithm.ED25519); + +const transaction = new NativeTransferBuilder() + .from(sender.publicKey) + .target( + PublicKey.fromHex( + '0202f5a92ab6da536e7b1a351406f3744224bec85d7acbab1497b65de48a1a707b64' + ) + ) + .amount('25000000000') // Amount in motes + .id(Date.now()) + .chainName('casper-net-1') + .payment(100_000_000) + .build(); + +await transaction.sign(privateKey); + +try { + const result = await rpcClient.putTransaction(transaction); + console.log(`Transaction Hash: ${result.transactionHash}`); +} catch (e) { + console.error(e); +} +``` diff --git a/src/types/Deploy.ts b/src/types/Deploy.ts index b4c3c39e..50bb6b47 100644 --- a/src/types/Deploy.ts +++ b/src/types/Deploy.ts @@ -269,7 +269,9 @@ export class Deploy { * @param keys The private key used to sign the deploy. */ public async sign(keys: PrivateKey): Promise { - const signatureBytes = await keys.sign(this.hash.toBytes()); + const signatureBytes = await keys.signAndAddAlgorithmBytes( + this.hash.toBytes() + ); const signature = new HexBytes(signatureBytes); this.approvals.push(new Approval(keys.publicKey, signature)); } diff --git a/src/types/Transaction.test.ts b/src/types/Transaction.test.ts index b1a10632..22288871 100644 --- a/src/types/Transaction.test.ts +++ b/src/types/Transaction.test.ts @@ -24,6 +24,7 @@ import { CLValueUInt64 } from './clvalue'; import { TransactionV1Payload } from './TransactionV1Payload'; +import { NativeTransferBuilder } from './TransactionBuilder'; describe('Test Transaction', () => { it('should create a TransactionV1 with correct payload instance', async () => { @@ -90,4 +91,32 @@ describe('Test Transaction', () => { expect(transaction.payload.fields.scheduling).to.deep.equal(scheduling); expect(transaction.payload.fields.entryPoint).to.deep.equal(entryPoint); }); + + it('should create native transfer TransactionV1 with builder', async () => { + const sender = await PrivateKey.generate(KeyAlgorithm.ED25519); + + const transaction = new NativeTransferBuilder() + .from(sender.publicKey) + .target( + PublicKey.fromHex( + '0202f5a92ab6da536e7b1a351406f3744224bec85d7acbab1497b65de48a1a707b64' + ) + ) + .amount('25000000000') + .id(Date.now()) + .chainName('casper-net-1') + .payment(100_000_000) + .build(); + + await transaction.sign(sender); + + const transactionV1 = transaction.getTransactionV1()!; + const transactionPaymentAmount = transactionV1.payload.fields.args.args + .get('amount')! + .toString(); + + assert.deepEqual(transaction.approvals[0].signer, sender.publicKey); + assert.deepEqual(parseInt(transactionPaymentAmount, 10), 25000000000); + expect(transactionV1.payload.chainName).to.deep.equal('casper-net-1'); + }); }); diff --git a/src/types/Transaction.ts b/src/types/Transaction.ts index 7e20b8d9..0e4435d6 100644 --- a/src/types/Transaction.ts +++ b/src/types/Transaction.ts @@ -170,7 +170,9 @@ export class TransactionV1 { * @param keys The private key to sign the transaction. */ async sign(keys: PrivateKey): Promise { - const signatureBytes = await keys.sign(this.hash.toBytes()); + const signatureBytes = await keys.signAndAddAlgorithmBytes( + this.hash.toBytes() + ); const signature = new HexBytes(signatureBytes); if (!this.approvals) { @@ -467,7 +469,10 @@ export class Transaction { } public getTransactionWrapper(): TransactionWrapper { - return new TransactionWrapper(this.originDeployV1, this.originTransactionV1); + return new TransactionWrapper( + this.originDeployV1, + this.originTransactionV1 + ); } /** @@ -489,7 +494,9 @@ export class Transaction { * @param key The private key to sign the transaction. */ async sign(key: PrivateKey): Promise { - const signatureBytes = await key.sign(this.hash.toBytes()); + const signatureBytes = await key.signAndAddAlgorithmBytes( + this.hash.toBytes() + ); this.setSignature(signatureBytes, key.publicKey); } diff --git a/src/types/TransactionBuilder.md b/src/types/TransactionBuilder.md new file mode 100644 index 00000000..d98e3de6 --- /dev/null +++ b/src/types/TransactionBuilder.md @@ -0,0 +1,173 @@ +# Transaction Builders + +TransactionBuilder contains classes and methods for building and managing Casper blockchain transactions. The provided classes extend the `TransactionBuilder` base class to create specific types of transactions, such as transfers, bids, delegations, and contract calls. + +## Table of Contents + +- [Overview](#overview) +- [Classes](#classes) + - [TransactionBuilder](#transactionv1builder) + - [NativeTransferBuilder](#nativetransferbuilder) + - [NativeAddBidBuilder](#nativeaddbidbuilder) + - [NativeWithdrawBidBuilder](#nativewithdrawbidbuilder) + - [NativeDelegateBuilder](#nativedelegatebuilder) + - [NativeUndelegateBuilder](#nativeundelegatebuilder) + - [NativeRedelegateBuilder](#nativeredelegatebuilder) + - [NativeActivateBidBuilder](#nativeactivatebidbuilder) + - [NativeChangeBidPublicKeyBuilder](#nativechangebidpublickeybuilder) + - [ContractCallBuilder](#contractcallbuilder) + - [SessionBuilder](#sessionbuilder) + +## Overview + +The provided classes allow developers to build, customize, and execute transactions on the Casper blockchain. By using builder patterns, developers can chain methods to configure each aspect of the transaction before calling `build()` to create the final [Transaction](./Transaction.ts) instance. + +## Classes + +### TransactionBuilder + +The abstract base class for all transaction builders. This class provides common methods for setting basic transaction parameters such as: + +- `from(publicKey: PublicKey)`: Sets the initiator of the transaction. +- `chainName(chainName: string)`: Sets the name of the target blockchain. +- `timestamp(timestamp: Timestamp)`: Sets the timestamp for the transaction. +- `ttl(ttl: number)`: Sets the transaction's time-to-live (TTL). +- `payment(paymentAmount: number)`: Sets the payment details. + +### NativeTransferBuilder + +Used to create native transfers on the Casper blockchain. + +#### Key Methods: + +- `target(publicKey: PublicKey)`: Sets the transfer target using a public key. +- `targetAccountHash(accountHashKey: AccountHash)`: Sets the transfer target using an account hash. +- `amount(amount: BigNumber | string)`: Sets the amount to be transferred. +- `id(id: number)`: Sets the optional ID for the transfer. + +### NativeAddBidBuilder + +Used to create an add-bid transaction. + +#### Key Methods: + +- `validator(publicKey: PublicKey)`: Sets the validator's public key. +- `amount(amount: BigNumber | string)`: Sets the bid amount. +- `delegationRate(delegationRate: number)`: Sets the delegation rate. +- `minimumDelegationAmount(amount: BigNumberish)`: Sets the minimum delegation amount. +- `maximumDelegationAmount(amount: BigNumberish)`: Sets the maximum delegation amount. + +### NativeWithdrawBidBuilder + +Used to create a withdraw-bid transaction. + +#### Key Methods: + +- `validator(publicKey: PublicKey)`: Sets the validator's public key. +- `amount(amount: BigNumber | string)`: Sets the amount to be withdrawn. + +### NativeDelegateBuilder + +Used to create a delegate transaction. + +#### Key Methods: + +- `validator(publicKey: PublicKey)`: Sets the validator's public key. +- `amount(amount: BigNumber | string)`: Sets the delegation amount. + +### NativeUndelegateBuilder + +Used to create an undelegate transaction. + +#### Key Methods: + +- `validator(publicKey: PublicKey)`: Sets the validator's public key. +- `amount(amount: BigNumber | string)`: Sets the amount to be undelegated. + +### NativeRedelegateBuilder + +Used to create a redelegate transaction. + +#### Key Methods: + +- `validator(publicKey: PublicKey)`: Sets the validator's public key. +- `newValidator(publicKey: PublicKey)`: Sets the new validator's public key. +- `amount(amount: BigNumber | string)`: Sets the redelegation amount. + +### NativeActivateBidBuilder + +Used to create an activate-bid transaction. + +#### Key Methods: + +- `validator(publicKey: PublicKey)`: Sets the validator's public key. + +### NativeChangeBidPublicKeyBuilder + +Used to change the public key for an existing bid. + +#### Key Methods: + +- `previousPublicKey(publicKey: PublicKey)`: Sets the previous public key. +- `newPublicKey(publicKey: PublicKey)`: Sets the new public key. + +### ContractCallBuilder + +Used to create and call stored contracts. + +#### Key Methods: + +- `byHash(contractHash: string)`: Calls a contract by its hash. +- `byName(name: string)`: Calls a contract by its name. +- `byPackageHash(contractHash: string, version?: number)`: Calls a contract within a package by its hash. +- `byPackageName(name: string, version?: number)`: Calls a contract within a package by its name. +- `entryPoint(name: string)`: Sets the entry point for the contract call. +- `runtimeArgs(args: Args)`: Sets the runtime arguments for the contract call. + +### SessionBuilder + +Used to create session transactions. + +#### Key Methods: + +- `wasm(wasmBytes: Uint8Array)`: Sets the session WebAssembly (WASM) module. +- `installOrUpgrade()`: Sets the transaction as an install or upgrade. +- `runtimeArgs(args: Args)`: Sets the runtime arguments for the session. + +## Usage Example + +```typescript +import { + PublicKey, + Args, + PrivateKey, + NativeTransferBuilder, + ContractCallBuilder +} from 'casper-js-sdk'; + +const sender = await PrivateKey.generate(KeyAlgorithm.ED25519); + +// Create a simple native transfer +const transaction = new NativeTransferBuilder() + .from(sender.publicKey) + .target(PublicKey.fromHex('abcdef0123456789')) + .amount('25000000000') // Amount in motes + .id(Date.now()) + .chainName('casper-net-1') + .payment(100_000_000) + .build(); + +await transaction.sign(sender); + +// Create a contract call +const contractCallTransaction = new ContractCallBuilder() + .from(sender.publicKey) + .byHash('example_contract') + .entryPoint('unstake') + .runtimeArgs(Args.fromMap({ key: 'value' })) + .payment(3_000000000) // Amount in motes + .chainName('casper-net-1') + .build(); + +await contractCallTransaction.sign(sender); +``` diff --git a/src/types/TransactionBuilder.ts b/src/types/TransactionBuilder.ts new file mode 100644 index 00000000..a6bed25d --- /dev/null +++ b/src/types/TransactionBuilder.ts @@ -0,0 +1,622 @@ +import { BigNumber, BigNumberish } from '@ethersproject/bignumber'; + +import { InitiatorAddr } from './InitiatorAddr'; +import { PaymentLimitedMode, PricingMode } from './PricingMode'; +import { + ByPackageHashInvocationTarget, + ByPackageNameInvocationTarget, + SessionTarget, + StoredTarget, + TransactionInvocationTarget, + TransactionRuntime, + TransactionTarget +} from './TransactionTarget'; +import { + TransactionEntryPoint, + TransactionEntryPointEnum +} from './TransactionEntryPoint'; +import { TransactionScheduling } from './TransactionScheduling'; +import { Args } from './Args'; +import { PublicKey } from './keypair'; +import { AccountHash, Hash } from './key'; +import { Transaction, TransactionV1 } from './Transaction'; +import { TransactionV1Payload } from './TransactionV1Payload'; +import { Duration, Timestamp } from './Time'; +import { + CLValue, + CLValueByteArray, + CLValueOption, + CLValueUInt32, + CLValueUInt512, + CLValueUInt64, + CLValueUInt8 +} from './clvalue'; + +/** + * Abstract base class for building Transaction V1 instances. + */ +abstract class TransactionBuilder> { + protected _initiatorAddr!: InitiatorAddr; + protected _chainName!: string; + protected _timestamp = new Timestamp(new Date()); + protected _ttl = new Duration(1800000); + protected _pricingMode!: PricingMode; + protected _invocationTarget!: TransactionTarget; + protected _entryPoint!: TransactionEntryPoint; + protected _scheduling: TransactionScheduling = new TransactionScheduling({}); // Standard + protected _runtimeArgs: Args; + + /** + * Sets the initiator address using a public key. + */ + public from(publicKey: PublicKey): T { + this._initiatorAddr = new InitiatorAddr(publicKey); + return (this as unknown) as T; + } + + /** + * Sets the initiator address using an account hash. + */ + public fromAccountHash(accountHashKey: AccountHash): T { + this._initiatorAddr = new InitiatorAddr(undefined, accountHashKey); + return (this as unknown) as T; + } + + /** + * Sets the chain name for the transaction. + */ + public chainName(chainName: string): T { + this._chainName = chainName; + return (this as unknown) as T; + } + + /** + * Sets the timestamp for the transaction. + */ + public timestamp(timestamp: Timestamp): T { + this._timestamp = timestamp; + return (this as unknown) as T; + } + + /** + * Sets the time-to-live for the transaction. + */ + public ttl(ttl: number): T { + this._ttl = new Duration(ttl); + return (this as unknown) as T; + } + + /** + * Sets the payment amount for the transaction. + */ + public payment(paymentAmount: number): T { + const pricingMode = new PricingMode(); + const paymentLimited = new PaymentLimitedMode(); + paymentLimited.standardPayment = true; + paymentLimited.paymentAmount = paymentAmount; + paymentLimited.gasPriceTolerance = 1; + + pricingMode.paymentLimited = paymentLimited; + this._pricingMode = pricingMode; + return (this as unknown) as T; + } + + /** + * Builds and returns the Transaction instance. + */ + public build(): Transaction { + const transactionPayload = TransactionV1Payload.build({ + initiatorAddr: this._initiatorAddr, + timestamp: this._timestamp, + ttl: this._ttl, + chainName: this._chainName, + pricingMode: this._pricingMode, + args: this._runtimeArgs, + transactionTarget: this._invocationTarget, + entryPoint: this._entryPoint, + scheduling: this._scheduling + }); + + const transactionV1 = TransactionV1.makeTransactionV1(transactionPayload); + return Transaction.fromTransactionV1(transactionV1); + } +} + +/** + * Builder for creating Native Transfer transactions. + */ +export class NativeTransferBuilder extends TransactionBuilder< + NativeTransferBuilder +> { + private _target!: CLValue; + private _amount: CLValue = CLValueUInt512.newCLUInt512('0'); + private _idTransfer?: number; + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); // Native + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.Transfer + ); + } + + /** + * Sets the target public key for the transfer. + */ + public target(publicKey: PublicKey): NativeTransferBuilder { + this._target = CLValue.newCLPublicKey(publicKey); + return this; + } + + /** + * Sets the target account hash for the transfer. + */ + public targetAccountHash(accountHashKey: AccountHash): NativeTransferBuilder { + this._target = CLValueByteArray.newCLByteArray(accountHashKey.toBytes()); + return this; + } + + /** + * Sets the amount to transfer. + */ + public amount(amount: BigNumber | string): NativeTransferBuilder { + this._amount = CLValueUInt512.newCLUInt512(amount); + return this; + } + + /** + * Sets the transfer ID. + */ + public id(id: number): NativeTransferBuilder { + this._idTransfer = id; + return this; + } + + /** + * Builds and returns the Native Transfer transaction. + */ + public build(): Transaction { + const runtimeArgs = Args.fromMap({}); + + runtimeArgs.insert('target', this._target); + runtimeArgs.insert('amount', this._amount); + + if (this._idTransfer) { + runtimeArgs.insert( + 'id', + CLValueOption.newCLOption(CLValueUInt64.newCLUint64(this._idTransfer)) + ); + } + + this._runtimeArgs = runtimeArgs; + return super.build(); + } +} + +export class NativeAddBidBuilder extends TransactionBuilder< + NativeAddBidBuilder +> { + private _validator!: CLValue; + private _amount!: CLValue; + private _delegationRate!: CLValue; + private _minimumDelegationAmount?: CLValue; + private _maximumDelegationAmount?: CLValue; + private _reservedSlots?: CLValue; + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); // Native + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.AddBid + ); + } + + public validator(publicKey: PublicKey): NativeAddBidBuilder { + this._validator = CLValue.newCLPublicKey(publicKey); + return this; + } + + public amount(amount: BigNumber | string): NativeAddBidBuilder { + this._amount = CLValueUInt512.newCLUInt512(amount); + return this; + } + + public delegationRate(delegationRate: number): NativeAddBidBuilder { + this._delegationRate = CLValueUInt8.newCLUint8(delegationRate); + return this; + } + + public minimumDelegationAmount( + minimumDelegationAmount: BigNumberish + ): NativeAddBidBuilder { + this._minimumDelegationAmount = CLValueUInt64.newCLUint64( + minimumDelegationAmount + ); + return this; + } + + public maximumDelegationAmount( + maximumDelegationAmount: BigNumberish + ): NativeAddBidBuilder { + this._maximumDelegationAmount = CLValueUInt64.newCLUint64( + maximumDelegationAmount + ); + return this; + } + + public reservedSlots(reservedSlots: BigNumber): NativeAddBidBuilder { + this._reservedSlots = CLValueUInt32.newCLUInt32(reservedSlots); + return this; + } + + public build(): Transaction { + const runtimeArgs = Args.fromMap({}); + + runtimeArgs.insert('public_key', this._validator); + runtimeArgs.insert('amount', this._amount); + runtimeArgs.insert('delegation_rate', this._delegationRate); + + if (this._minimumDelegationAmount) { + runtimeArgs.insert( + 'minimum_delegation_amount', + this._minimumDelegationAmount + ); + } + + if (this._maximumDelegationAmount) { + runtimeArgs.insert( + 'maximum_delegation_amount', + this._maximumDelegationAmount + ); + } + + if (this._reservedSlots) { + runtimeArgs.insert('reserved_slots', this._reservedSlots); + } + + this._runtimeArgs = runtimeArgs; + + return super.build(); + } +} + +export class NativeWithdrawBidBuilder extends TransactionBuilder< + NativeWithdrawBidBuilder +> { + private _validator!: CLValue; + private _amount: CLValue = CLValueUInt512.newCLUInt512('0'); + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); // Native + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.WithdrawBid + ); + } + + public validator(publicKey: PublicKey): NativeWithdrawBidBuilder { + this._validator = CLValue.newCLPublicKey(publicKey); + return this; + } + + public amount(amount: BigNumber | string): NativeWithdrawBidBuilder { + this._amount = CLValueUInt512.newCLUInt512(amount); + return this; + } + + public build(): Transaction { + this._runtimeArgs = Args.fromMap({ + public_key: this._validator, + amount: this._amount + }); + + return super.build(); + } +} + +export class NativeDelegateBuilder extends TransactionBuilder< + NativeDelegateBuilder +> { + private _validator!: CLValue; + private _amount: CLValue = CLValueUInt512.newCLUInt512('0'); + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.Delegate + ); + } + + public validator(publicKey: PublicKey): NativeDelegateBuilder { + this._validator = CLValue.newCLPublicKey(publicKey); + return this; + } + + public amount(amount: BigNumber | string): NativeDelegateBuilder { + this._amount = CLValueUInt512.newCLUInt512(amount); + return this; + } + + public build(): Transaction { + if (!this._initiatorAddr.publicKey) { + throw new Error('Initiator addr is not specified'); + } + + this._runtimeArgs = Args.fromMap({ + delegator: CLValue.newCLPublicKey(this._initiatorAddr.publicKey), + validator: this._validator, + amount: this._amount + }); + + return super.build(); + } +} + +export class NativeUndelegateBuilder extends TransactionBuilder< + NativeUndelegateBuilder +> { + private _validator!: CLValue; + private _amount: CLValue = CLValueUInt512.newCLUInt512('0'); + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.Undelegate + ); + } + + public validator(publicKey: PublicKey): NativeUndelegateBuilder { + this._validator = CLValue.newCLPublicKey(publicKey); + return this; + } + + public amount(amount: BigNumber | string): NativeUndelegateBuilder { + this._amount = CLValueUInt512.newCLUInt512(amount); + return this; + } + + public build(): Transaction { + if (!this._initiatorAddr.publicKey) { + throw new Error('Initiator addr is not specified'); + } + + this._runtimeArgs = Args.fromMap({ + delegator: CLValue.newCLPublicKey(this._initiatorAddr.publicKey), + validator: this._validator, + amount: this._amount + }); + + return super.build(); + } +} + +export class NativeRedelegateBuilder extends TransactionBuilder< + NativeRedelegateBuilder +> { + private _validator!: CLValue; + private _newValidator!: CLValue; + private _amount: CLValue = CLValueUInt512.newCLUInt512('0'); + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.Redelegate + ); + } + + public validator(publicKey: PublicKey): NativeRedelegateBuilder { + this._validator = CLValue.newCLPublicKey(publicKey); + return this; + } + + public newValidator(publicKey: PublicKey): NativeRedelegateBuilder { + this._newValidator = CLValue.newCLPublicKey(publicKey); + return this; + } + + public amount(amount: BigNumber | string): NativeRedelegateBuilder { + this._amount = CLValueUInt512.newCLUInt512(amount); + return this; + } + + public build(): Transaction { + if (!this._initiatorAddr.publicKey) { + throw new Error('Initiator addr is not specified'); + } + + this._runtimeArgs = Args.fromMap({ + delegator: CLValue.newCLPublicKey(this._initiatorAddr.publicKey), + validator: this._validator, + amount: this._amount, + new_validator: this._newValidator + }); + + return super.build(); + } +} + +export class NativeActivateBidBuilder extends TransactionBuilder< + NativeActivateBidBuilder +> { + private _validator!: CLValue; + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); // Native + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.ActivateBid + ); + } + + public validator(publicKey: PublicKey): NativeActivateBidBuilder { + this._validator = CLValue.newCLPublicKey(publicKey); + return this; + } + + public build(): Transaction { + this._runtimeArgs = Args.fromMap({ + validator: this._validator + }); + + return super.build(); + } +} + +export class NativeChangeBidPublicKeyBuilder extends TransactionBuilder< + NativeChangeBidPublicKeyBuilder +> { + private _public_key!: CLValue; + private _new_public_key!: CLValue; + + constructor() { + super(); + this._invocationTarget = new TransactionTarget({}); + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.ChangeBidPublicKey + ); + } + + public previousPublicKey( + publicKey: PublicKey + ): NativeChangeBidPublicKeyBuilder { + this._public_key = CLValue.newCLPublicKey(publicKey); + return this; + } + + public newPublicKey(publicKey: PublicKey): NativeChangeBidPublicKeyBuilder { + this._new_public_key = CLValue.newCLPublicKey(publicKey); + return this; + } + + public build(): Transaction { + this._runtimeArgs = Args.fromMap({ + public_key: this._public_key, + new_public_key: this._new_public_key + }); + + return super.build(); + } +} + +export class ContractCallBuilder extends TransactionBuilder< + ContractCallBuilder +> { + constructor() { + super(); + } + + public byHash(contractHash: string): ContractCallBuilder { + const invocationTarget = new TransactionInvocationTarget(); + invocationTarget.byHash = Hash.fromHex(contractHash); + + const storedTarget = new StoredTarget(); + storedTarget.id = invocationTarget; + storedTarget.runtime = TransactionRuntime.vmCasperV1(); + + this._invocationTarget = new TransactionTarget(undefined, storedTarget); + return this; + } + + public byName(name: string): ContractCallBuilder { + const invocationTarget = new TransactionInvocationTarget(); + invocationTarget.byName = name; + + const storedTarget = new StoredTarget(); + storedTarget.id = invocationTarget; + storedTarget.runtime = TransactionRuntime.vmCasperV1(); + + this._invocationTarget = new TransactionTarget(undefined, storedTarget); + return this; + } + + public byPackageHash( + contractHash: string, + version?: number + ): ContractCallBuilder { + const packageHashInvocationTarget = new ByPackageHashInvocationTarget(); + packageHashInvocationTarget.addr = Hash.fromHex(contractHash); + packageHashInvocationTarget.version = version; + const transactionInvocationTarget = new TransactionInvocationTarget(); + transactionInvocationTarget.byPackageHash = packageHashInvocationTarget; + + const storedTarget = new StoredTarget(); + + storedTarget.id = transactionInvocationTarget; + storedTarget.runtime = TransactionRuntime.vmCasperV1(); + + this._invocationTarget = new TransactionTarget(undefined, storedTarget); + return this; + } + + public byPackageName(name: string, version?: number): ContractCallBuilder { + const packageNameInvocationTarget = new ByPackageNameInvocationTarget(); + packageNameInvocationTarget.name = name; + packageNameInvocationTarget.version = version; + const transactionInvocationTarget = new TransactionInvocationTarget(); + transactionInvocationTarget.byPackageName = packageNameInvocationTarget; + + const storedTarget = new StoredTarget(); + + storedTarget.id = transactionInvocationTarget; + storedTarget.runtime = TransactionRuntime.vmCasperV1(); + + this._invocationTarget = new TransactionTarget(undefined, storedTarget); + + return this; + } + + public entryPoint(name: string): ContractCallBuilder { + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.Custom, + name + ); + return this; + } + + public runtimeArgs(args: Args): ContractCallBuilder { + this._runtimeArgs = args; + return this; + } +} + +export class SessionBuilder extends TransactionBuilder { + private _isInstallOrUpgrade = false; + + constructor() { + super(); + this._entryPoint = new TransactionEntryPoint( + TransactionEntryPointEnum.Call + ); + } + + public wasm(wasmBytes: Uint8Array): SessionBuilder { + const sessionTarget = new SessionTarget(); + sessionTarget.moduleBytes = wasmBytes; + sessionTarget.isInstallUpgrade = this._isInstallOrUpgrade; + sessionTarget.runtime = TransactionRuntime.vmCasperV1(); + + this._invocationTarget = new TransactionTarget( + undefined, + undefined, + sessionTarget + ); + + return this; + } + + public installOrUpgrade(): SessionBuilder { + this._isInstallOrUpgrade = true; + if (this._invocationTarget?.session) { + this._invocationTarget.session.isInstallUpgrade = true; + } + return this; + } + + public runtimeArgs(args: Args): SessionBuilder { + this._runtimeArgs = args; + return this; + } +} diff --git a/src/types/index.ts b/src/types/index.ts index 969c0e63..b485a774 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -40,3 +40,4 @@ export * from './key'; export * from './clvalue'; export * from './keypair'; export * from './ContractWasm'; +export * from './TransactionBuilder';