Skip to content

Commit

Permalink
Improve Transaction creation from JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
Comp0te committed Dec 12, 2024
1 parent 0717b57 commit af3a92a
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 14 deletions.
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,12 +176,14 @@ const transactionPayload = TransactionV1Payload.build({
pricingMode
});

const transaction = TransactionV1.makeTransactionV1(
const transactionV1 = TransactionV1.makeTransactionV1(
transactionPayload
);
await transaction.sign(privateKey);
await transactionV1.sign(privateKey);

const result = await rpcClient.putTransactionV1(transaction);
const tx = Transaction.fromTransactionV1(transactionV1);

const result = await rpcClient.putTransaction(tx);

console.log(`Transaction Hash: ${result.transactionHash}`);
```
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import {
PurseIdentifier,
RpcRequest
} from './request';
import { TransactionV1, Deploy, PublicKey } from '../types';
import { Deploy, PublicKey, Transaction } from '../types';

export interface ClientPOS {
getLatestAuctionInfo(): Promise<StateGetAuctionInfoResult>;
Expand Down Expand Up @@ -226,7 +226,7 @@ export interface ClientInformational {

export interface ClientTransactional {
putDeploy(deploy: Deploy): Promise<PutDeployResult>;
putTransactionV1(transaction: TransactionV1): Promise<PutTransactionResult>;
putTransaction(transaction: Transaction): Promise<PutTransactionResult>;
}

export interface IClient
Expand Down
4 changes: 2 additions & 2 deletions src/rpc/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,10 @@ export class PutDeployRequest {
@jsonObject
export class PutTransactionRequest {
@jsonMember({ constructor: TransactionWrapper })
transaction: TransactionWrapper;
transactionWrapper: TransactionWrapper;

constructor(transaction: TransactionWrapper) {
this.transaction = transaction;
this.transactionWrapper = transaction;
}
}

Expand Down
11 changes: 5 additions & 6 deletions src/rpc/rpc_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,10 @@ import {
import { IDValue } from './id_value';
import {
TransactionHash,
TransactionV1,
TransactionWrapper,
Deploy,
PublicKey,
Hash
Hash,
Transaction
} from '../types';

export class RpcClient implements IClient {
Expand Down Expand Up @@ -903,12 +902,12 @@ export class RpcClient implements IClient {
return result;
}

async putTransactionV1(
transaction: TransactionV1
async putTransaction(
transaction: Transaction
): Promise<PutTransactionResult> {
const serializer = new TypedJSON(PutTransactionRequest);
const transactionRequestParam = new PutTransactionRequest(
new TransactionWrapper(undefined, transaction)
transaction.getTransactionWrapper()
);

const resp = await this.processRequest<PutTransactionRequest>(
Expand Down
85 changes: 84 additions & 1 deletion src/types/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,6 @@ export class Transaction {
* @param entryPoint The entry point of the transaction.
* @param scheduling The scheduling information for the transaction.
* @param approvals The list of approvals for this transaction.
* @param category The category of the transaction, indicating its type (e.g., minting, auction).
* @param originTransactionV1 The original TransactionV1, if applicable.
* @param originDeployV1 The original deploy, if applicable.
*/
Expand Down Expand Up @@ -437,6 +436,18 @@ export class Transaction {

this.originDeployV1 = originDeployV1;
this.originTransactionV1 = originTransactionV1;

if (!(this.originDeployV1 || this.originTransactionV1)) {
throw new Error(
'Incorrect Transaction instance. Missing originTransactionV1 or originDeploy'
);
}

if (this.originDeployV1 && this.originTransactionV1) {
throw new Error(
'Incorrect Transaction instance. Should be only one of originTransactionV1 or originDeploy'
);
}
}

/**
Expand All @@ -455,6 +466,53 @@ export class Transaction {
return this.originTransactionV1;
}

public getTransactionWrapper(): TransactionWrapper {
return new TransactionWrapper(this.originDeployV1, this.originTransactionV1);
}

/**
* Validates the transaction by checking the transaction hash and the approval signatures.
* @throws {TransactionError} Throws errors if validation fails.
*/
public validate(): boolean {
if (this.originTransactionV1) {
return this.originTransactionV1.validate();
} else if (this.originDeployV1) {
return this.originDeployV1.validate();
}

throw new Error('Incorrect Transaction instance. Missing origin value');
}

/**
* Signs the transaction using the provided private key.
* @param key The private key to sign the transaction.
*/
async sign(key: PrivateKey): Promise<void> {
const signatureBytes = await key.sign(this.hash.toBytes());
this.setSignature(signatureBytes, key.publicKey);
}

/**
* Sets an already generated signature to the transaction.
* @param signature The Ed25519 or Secp256K1 signature.
* @param publicKey The public key used to generate the signature.
*/
setSignature(signature: Uint8Array, publicKey: PublicKey) {
const hex = new HexBytes(signature);
const approval = new Approval(publicKey, hex);

this.approvals.push(approval);

if (this.originTransactionV1) {
this.originTransactionV1.approvals.push(approval);
} else if (this.originDeployV1) {
this.originDeployV1.approvals.push(approval);
} else {
throw new Error('Incorrect Transaction instance. Missing origin value');
}
}

/**
* Converts a `TransactionV1` to a `Transaction` object.
* @param v1 The `TransactionV1` to convert.
Expand All @@ -477,6 +535,31 @@ export class Transaction {
undefined // originDeployV1 is not applicable for this method
);
}

/**
* Converts a `TransactionV1` to a `Transaction` object.
* @param deploy The `Deploy` to convert.
* @returns A new `Transaction` instance created from the given `Deploy`.
*/
static fromDeploy(deploy: Deploy): Transaction {
return Deploy.newTransactionFromDeploy(deploy);
}

static fromJson(json: any): Transaction {
try {
const txV1 = TransactionV1.fromJSON(json);

return Transaction.fromTransactionV1(txV1);
} catch (e) {}

try {
const deploy = Deploy.fromJSON(json);

return Transaction.fromDeploy(deploy);
} catch (e) {}

throw new Error("The JSON can't be parsed as a Transaction.");
}
}

/**
Expand Down

0 comments on commit af3a92a

Please sign in to comment.