-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tool 393 add relayer v 3 support #543
Changes from 3 commits
cfa0d5c
a971849
642b00a
b810a2a
d132706
684e44d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
import { Address } from "../address"; | ||
import { IPlainTransactionObject, ITransaction } from "../interface"; | ||
import { IContractResultItem, ITransactionEvent, ITransactionOnNetwork } from "../interfaceOfNetwork"; | ||
import { ResultsParser } from "../smartcontracts"; | ||
|
@@ -25,9 +26,11 @@ export class TransactionsConverter { | |
chainID: transaction.chainID.valueOf(), | ||
version: transaction.version, | ||
options: transaction.options == 0 ? undefined : transaction.options, | ||
relayer: !transaction.relayer || transaction.relayer.isEmpty() ? undefined : transaction.relayer.toBech32(), | ||
guardian: transaction.guardian ? transaction.guardian : undefined, | ||
signature: this.toHexOrUndefined(transaction.signature), | ||
guardianSignature: this.toHexOrUndefined(transaction.guardianSignature), | ||
relayerSignature: this.toHexOrUndefined(transaction.relayerSignature), | ||
}; | ||
|
||
return plainObject; | ||
|
@@ -46,6 +49,7 @@ export class TransactionsConverter { | |
nonce: BigInt(object.nonce), | ||
value: BigInt(object.value || ""), | ||
receiver: object.receiver, | ||
relayer: object.relayer ? Address.newFromBech32(object.relayer) : Address.empty(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have it the same as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, now I see, cannot be same as guardian, since that's a string 👍 |
||
receiverUsername: this.bufferFromBase64(object.receiverUsername).toString(), | ||
sender: object.sender, | ||
senderUsername: this.bufferFromBase64(object.senderUsername).toString(), | ||
|
@@ -58,6 +62,7 @@ export class TransactionsConverter { | |
options: Number(object.options), | ||
signature: this.bufferFromHex(object.signature), | ||
guardianSignature: this.bufferFromHex(object.guardianSignature), | ||
relayerSignature: this.bufferFromHex(object.relayerSignature), | ||
}); | ||
|
||
return transaction; | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ | |
* Serializes a Transaction object to a Buffer. Handles low-level conversion logic and field-mappings as well. | ||
*/ | ||
serializeTransaction(transaction: Transaction): Buffer { | ||
const proto = require("./compiled").proto; | ||
|
||
const protoTransaction = this.convertToProtoMessage(transaction); | ||
const encoded = proto.Transaction.encode(protoTransaction).finish(); | ||
|
@@ -26,7 +26,7 @@ | |
} | ||
|
||
private convertToProtoMessage(transaction: ITransaction) { | ||
const proto = require("./compiled").proto; | ||
|
||
const receiverPubkey = new Address(transaction.receiver).getPublicKey(); | ||
const senderPubkey = new Address(transaction.sender).getPublicKey(); | ||
|
@@ -60,6 +60,11 @@ | |
protoTransaction.GuardianSignature = transaction.guardianSignature; | ||
} | ||
|
||
if (transaction.relayer && !transaction.relayer.isEmpty()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can refactor to have a mini private function |
||
protoTransaction.Relayer = transaction.relayer.getPublicKey(); | ||
protoTransaction.RelayerSignature = transaction.relayerSignature; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's extract to a function similar to the guardian check above, and also check if relayer signature is set. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we discussed about this internally and said it is not needed |
||
|
||
return protoTransaction; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,3 @@ | ||
import { UserPublicKey, UserVerifier } from "./wallet"; | ||
import BigNumber from "bignumber.js"; | ||
import { assert } from "chai"; | ||
import { Address } from "./address"; | ||
|
@@ -10,6 +9,7 @@ import { TokenTransfer } from "./tokens"; | |
import { Transaction } from "./transaction"; | ||
import { TransactionComputer } from "./transactionComputer"; | ||
import { TransactionPayload } from "./transactionPayload"; | ||
import { UserPublicKey, UserVerifier } from "./wallet"; | ||
|
||
describe("test transaction", async () => { | ||
let wallets: Record<string, TestWallet>; | ||
|
@@ -751,4 +751,44 @@ describe("test transaction", async () => { | |
assert.equal(isSignedByAlice, true); | ||
assert.equal(isSignedByBob, false); | ||
}); | ||
|
||
it("should serialize transaction with relayer", async () => { | ||
const transaction = new Transaction({ | ||
chainID: networkConfig.ChainID, | ||
sender: wallets.alice.address.bech32(), | ||
receiver: wallets.alice.address.bech32(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use |
||
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.bech32(), | ||
receiver: wallets.alice.address.bech32(), | ||
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)); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,6 @@ import { | |
INonce, | ||
IPlainTransactionObject, | ||
ISignature, | ||
ITransaction, | ||
ITransactionOptions, | ||
ITransactionPayload, | ||
ITransactionValue, | ||
|
@@ -20,8 +19,8 @@ import { | |
import { INetworkConfig } from "./interfaceOfNetwork"; | ||
import { TransactionOptions, TransactionVersion } from "./networkParams"; | ||
import { interpretSignatureAsBuffer } from "./signature"; | ||
import { TransactionPayload } from "./transactionPayload"; | ||
import { TransactionComputer } from "./transactionComputer"; | ||
import { TransactionPayload } from "./transactionPayload"; | ||
|
||
/** | ||
* An abstraction for creating and signing transactions. | ||
|
@@ -92,6 +91,11 @@ export class Transaction { | |
*/ | ||
public guardian: string; | ||
|
||
/** | ||
* The relayer, in address format, next version all the other addresses will not be string anymore. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be rephrased.
|
||
*/ | ||
public relayer?: Address; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe this doesn't need to be optional. Make it optional on the constructor and if not provided, set to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Indeed, optional - I see we have the same in PY 👍 https://github.com/multiversx/mx-sdk-py/blob/feat/next/multiversx_sdk/core/transaction.py#L49 |
||
|
||
/** | ||
* The signature. | ||
*/ | ||
|
@@ -102,6 +106,11 @@ export class Transaction { | |
*/ | ||
public guardianSignature: Uint8Array; | ||
|
||
/** | ||
* The signature of the guardian. | ||
*/ | ||
public relayerSignature: Uint8Array; | ||
|
||
/** | ||
* Creates a new Transaction object. | ||
*/ | ||
|
@@ -110,6 +119,7 @@ export class Transaction { | |
value?: ITransactionValue | bigint; | ||
sender: IAddress | string; | ||
receiver: IAddress | string; | ||
relayer?: Address; | ||
senderUsername?: string; | ||
receiverUsername?: string; | ||
gasPrice?: IGasPrice | bigint; | ||
|
@@ -121,6 +131,7 @@ export class Transaction { | |
guardian?: IAddress | string; | ||
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", | ||
|
@@ -137,9 +148,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 ? this.addressAsBech32(options.guardian) : ""; | ||
this.relayer = options.relayer?.isEmpty() ? undefined : options.relayer; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, now I see, cannot be same as guardian, since that's a string 👍 |
||
|
||
this.signature = options.signature || Buffer.from([]); | ||
this.guardianSignature = options.guardianSignature || Buffer.from([]); | ||
this.relayerSignature = options.relayerSignature || Buffer.from([]); | ||
} | ||
|
||
private addressAsBech32(address: IAddress | string): string { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have
relayer
andguardian
done in the same way. Which way should we choose?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, now I see, cannot be same as guardian, since that's a string 👍