Skip to content

Commit

Permalink
Merge branch 'main' into Feat/next
Browse files Browse the repository at this point in the history
  • Loading branch information
danielailie committed Dec 12, 2024
2 parents 87aef7f + 9bc160b commit 7d1b260
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 3 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@multiversx/sdk-core",
"version": "13.15.0",
"version": "13.16.0",
"description": "MultiversX SDK for JavaScript and TypeScript",
"author": "MultiversX",
"homepage": "https://multiversx.com",
Expand Down
2 changes: 2 additions & 0 deletions src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export interface IPlainTransactionObject {
receiverUsername?: string;
senderUsername?: string;
guardian?: string;
relayer?: string;
gasPrice: number;
gasLimit: number;
data?: string;
Expand All @@ -24,6 +25,7 @@ export interface IPlainTransactionObject {
options?: number;
signature?: string;
guardianSignature?: string;
relayerSignature?: string;
}

export interface ISignature {
Expand Down
64 changes: 64 additions & 0 deletions src/proto/compiled.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions src/proto/serializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,18 @@ export class ProtoSerializer {
protoTransaction.GuardianSignature = transaction.guardianSignature;
}

if (this.isRelayedTransaction(transaction)) {
protoTransaction.Relayer = transaction.relayer?.getPublicKey();
protoTransaction.RelayerSignature = transaction.relayerSignature;
}

return protoTransaction;
}

private isRelayedTransaction(transaction: ITransaction) {

Check failure on line 70 in src/proto/serializer.ts

View workflow job for this annotation

GitHub Actions / integration_tests

Cannot find name 'ITransaction'.
return !transaction.relayer.isEmpty();
}

/**
* Custom serialization, compatible with mx-chain-go.
*/
Expand Down
2 changes: 2 additions & 0 deletions src/proto/transaction.proto
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ message Transaction {
uint32 Options = 13;
bytes GuardianAddr = 14;
bytes GuardianSignature = 15;
bytes Relayer = 16;
bytes RelayerSignature = 17;
}
41 changes: 41 additions & 0 deletions src/transaction.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,8 +784,49 @@ describe("test transaction", async () => {
version: 2,
options: undefined,
guardian: undefined,
relayer: undefined,
signature: undefined,
guardianSignature: undefined,
relayerSignature: undefined,
});
});
it("should serialize transaction with relayer", async () => {
const transaction = new Transaction({
chainID: networkConfig.ChainID,
sender: wallets.alice.address,
receiver: wallets.alice.address,
relayer: wallets.bob.address,
gasLimit: 50000n,
value: 0n,
version: 2,
nonce: 89n,
});

const serializedTransactionBytes = transactionComputer.computeBytesForSigning(transaction);
const serializedTransaction = Buffer.from(serializedTransactionBytes).toString();

assert.equal(
serializedTransaction,
`{"nonce":89,"value":"0","receiver":"erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th","sender":"erd1qyu5wthldzr8wx5c9ucg8kjagg0jfs53s8nr3zpz3hypefsdd8ssycr6th","gasPrice":1000000000,"gasLimit":50000,"chainID":"D","version":2,"relayer":"erd1spyavw0956vq68xj8y4tenjpq2wd5a9p2c6j8gsz7ztyrnpxrruqzu66jx"}`,
);
});

it("should test relayed v3", async () => {
const transaction = new Transaction({
chainID: networkConfig.ChainID,
sender: wallets.alice.address,
receiver: wallets.alice.address,
senderUsername: "alice",
receiverUsername: "bob",
gasLimit: 80000n,
value: 0n,
version: 2,
nonce: 89n,
data: Buffer.from("hello"),
});

assert.isFalse(transactionComputer.isRelayedV3Transaction(transaction));
transaction.relayer = wallets.carol.address;
assert.isTrue(transactionComputer.isRelayedV3Transaction(transaction));
});
});
19 changes: 19 additions & 0 deletions src/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,12 @@ export class Transaction {
*/
public guardian: Address;

/**
* The relayer address.
* Note: in the next major version, `sender`, `receiver` and `guardian` will also have the type `Address`, instead of `string`.
*/
public relayer: Address;

/**
* The signature.
*/
Expand All @@ -86,6 +92,11 @@ export class Transaction {
*/
public guardianSignature: Uint8Array;

/**
* The signature of the relayer.
*/
public relayerSignature: Uint8Array;

/**
* Creates a new Transaction object.
*/
Expand All @@ -103,8 +114,10 @@ export class Transaction {
version?: number;
options?: number;
guardian?: Address;
relayer?: Address;
signature?: Uint8Array;
guardianSignature?: Uint8Array;
relayerSignature?: Uint8Array;
}) {
this.nonce = BigInt(options.nonce?.valueOf() || 0n);
// We still rely on "bigNumber" for value, because client code might be passing a BigNumber object as a legacy "ITransactionValue",
Expand All @@ -121,9 +134,11 @@ export class Transaction {
this.version = Number(options.version?.valueOf() || TRANSACTION_VERSION_DEFAULT);
this.options = Number(options.options?.valueOf() || TRANSACTION_OPTIONS_DEFAULT);
this.guardian = options.guardian ?? Address.empty();
this.relayer = options.relayer ? options.relayer : Address.empty();

this.signature = options.signature || Buffer.from([]);
this.guardianSignature = options.guardianSignature || Buffer.from([]);
this.relayerSignature = options.relayerSignature || Buffer.from([]);
}

/**
Expand Down Expand Up @@ -358,8 +373,10 @@ export class Transaction {
version: this.version,
options: this.options == 0 ? undefined : this.options,
guardian: this.guardian.isEmpty() ? undefined : this.guardian.toBech32(),
relayer: this.relayer.isEmpty() ? undefined : this.relayer.toBech32(),
signature: this.toHexOrUndefined(this.signature),
guardianSignature: this.toHexOrUndefined(this.guardianSignature),
relayerSignature: this.toHexOrUndefined(this.relayerSignature),
};

return plainObject;
Expand Down Expand Up @@ -389,6 +406,7 @@ export class Transaction {
sender: Address.newFromBech32(object.sender),
senderUsername: Buffer.from(object.senderUsername || "", "base64").toString(),
guardian: object.guardian ? Address.newFromBech32(object.guardian) : Address.empty(),
relayer: object.relayer ? Address.newFromBech32(object.relayer) : Address.empty(),
gasPrice: BigInt(object.gasPrice),
gasLimit: BigInt(object.gasLimit),
data: Buffer.from(object.data || "", "base64"),
Expand All @@ -397,6 +415,7 @@ export class Transaction {
options: Number(object.options),
signature: Buffer.from(object.signature || "", "hex"),
guardianSignature: Buffer.from(object.guardianSignature || "", "hex"),
relayerSignature: Buffer.from(object.relayerSignature || "", "hex"),
});

return transaction;
Expand Down
5 changes: 5 additions & 0 deletions src/transactionComputer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ export class TransactionComputer {
transaction.guardian = guardian;
}

isRelayedV3Transaction(transaction: Transaction) {
return !transaction.relayer.isEmpty();
}

applyOptionsForHashSigning(transaction: Transaction) {
if (transaction.version < MIN_TRANSACTION_VERSION_THAT_SUPPORTS_OPTIONS) {
transaction.version = MIN_TRANSACTION_VERSION_THAT_SUPPORTS_OPTIONS;
Expand Down Expand Up @@ -122,6 +126,7 @@ export class TransactionComputer {
obj.version = transaction.version;
obj.options = transaction.options ? transaction.options : undefined;
obj.guardian = transaction.guardian.isEmpty() ? undefined : transaction.guardian.toBech32();
obj.relayer = transaction.relayer?.isEmpty() ? undefined : transaction.relayer?.toBech32();

return obj;
}
Expand Down

0 comments on commit 7d1b260

Please sign in to comment.