const common = require("./common");
/**
* For more details about the {@link https://docs.goquorum.consensys.net/en/stable/Reference/APIs/PrivacyAPI Quorum Privacy APIs}
* @module eth
*/
function Eth(web3) {
web3.eth.extend({
methods: [
/**
* @function sendRawPrivateTransaction
* @param {String} Signed transaction data in HEX format
* @param {Object} privateData Private data to send
* @param {String[]} privateData.privateFor When sending a private transaction, an array of the recipients’ base64-encoded public keys.
* @param {Number} [privateData.privacyFlag=0] 0 for SP (default if not provided), 1 for PP, 3 for PSV
* @param {String[]} [privateData.mandatoryFor] an array of the recipients’ base64-encoded public keys
* @param {Function} [callback] If you pass a callback the HTTP request is made asynchronous.
* @return {String} The 32 Bytes transaction hash as HEX string
*/
{
name: "sendRawPrivateTransaction",
call: "eth_sendRawPrivateTransaction",
params: 2,
},
/**
* @function fillTransaction
* @param {Object} txObj - The transaction object to send:
* @param {String} txObj.from The address for the sending account.
* @param {String} [txObj.to] The destination address of the message,
* @param {Number|String|BigNumber} [txObj.value] The value transferred for the transaction in Wei, also the endowment if it’s a contract-creation transaction.
* @param {String} [txObj.data] Either a byte string containing the associated data of the message, or in the case of a contract-creation transaction, the initialisation code.
* @param {String[]} [txObj.privateFor] When sending a private transaction, an array of the recipients’ base64-encoded public keys.
* @return {Object} raw: RLP encoded bytes for the passed transaction object and tx : transaction object
*/
{
name: "fillTransaction",
call: "eth_fillTransaction",
params: 1,
inputFormatter: [web3.extend.formatters.inputTransactionFormatter],
},
/**
* @function storageRoot
* @param {String} address The address to fetch the storage root from in hex
* @param {String} [block="latest"] The block number to fetch the storage root from in hex
* @return {String} 32 Bytes storage root hash as hex string.
*/
{
name: "storageRoot",
call: "eth_storageRoot",
params: 2,
inputFormatter: [
web3.extend.formatters.inputAddressFormatter,
web3.extend.formatters.inputDefaultBlockNumberFormatter,
],
},
/**
* @function getQuorumPayload
* @param {String} id the HEX formatted generated Sha3-512 hash of the encrypted payload from the Private Transaction Manager. This is seen in the transaction as the input field
* @return {String} unencrypted transaction payload in HEX format.
*/
{
name: "getQuorumPayload",
call: "eth_getQuorumPayload",
params: 1,
},
/**
* @function sendTransactionAsync
* @param {Object} txObj Transaction Object to send
* @return {String}
*/
{
name: "sendTransactionAsync",
call: "eth_sendTransactionAsync",
params: 1,
inputFormatter: [web3.extend.formatters.inputTransactionFormatter],
},
/**
* @function getContractPrivacyMetadata
* @param {String} contractAddress
* @return {Object}
*/
{
name: "getContractPrivacyMetadata",
call: "eth_getContractPrivacyMetadata",
params: 1,
inputFormatter: [web3.extend.formatters.inputAddressFormatter],
},
/**
* @function distributePrivateTransaction
* @param {String} privateTxn Signed private transaction in hex format
* @param {Object} privateData Private data to send
* @param {String[]} privateData.privateFor An array of the recipients’ base64-encoded public keys.
* @param {String[]} [privateData.privateFrom] The sending party’s base64-encoded public key to use (Privacy Manager default if not provided).
* @param {Number} [privateData.privacyFlag=0] 0 for SP (default if not provided), 1 for PP, 3 for PSV
* @param {String[]} [privateData.mandatoryFor] an array of the recipients’ base64-encoded public keys
* @return {String} Transaction Manager hash to be used as a privacy marker transaction's `data` when externally signing..
*/
{
name: "distributePrivateTransaction",
call: "eth_distributePrivateTransaction",
params: 2,
},
/**
* @function getPrivacyPrecompileAddress
* @return {String} Contract address for the privacy precompile in hex format.
*/
{
name: "getPrivacyPrecompileAddress",
call: "eth_getPrivacyPrecompileAddress",
params: 0,
},
/**
* @function getPrivateTransactionByHash
* @param {String} hash Privacy marker transaction's hash in HEX format.
* @return {Transaction} private transaction (will be nil if caller is not a participant).
*/
{
name: "getPrivateTransactionByHash",
call: "eth_getPrivateTransactionByHash",
params: 1,
},
/**
* @function getPrivateTransactionReceipt
* @param {String} hash Privacy marker transaction's hash in HEX format.
* @return {Receipt} private transaction receipt (will be nil if caller is not a participant).
*/
{
name: "getPrivateTransactionReceipt",
call: "eth_getPrivateTransactionReceipt",
params: 1,
},
/**
* @function getPSI
* @return {String} the private state identifier (PSI)
*/
{
name: "getPSI",
call: "eth_getPSI",
params: 0,
},
],
});
// Use the web3 provider to directly call eth_sendTransaction in the node.
// This is necessary as web3.eth.sendTransaction doesn't work with Privacy Marker Transactions.
const sendTransactionUsingProvider = async (txnObject, callback) => {
const provider = web3.eth.currentProvider;
const jsonrpcPayload = {
jsonrpc: "2.0",
id: 3,
method: "eth_sendTransaction",
params: [txnObject],
};
const callSend = (sendParam) => {
return new Promise((resolve, reject) => {
try {
provider.send(sendParam, (err, data) => {
if (err) {
reject(err);
}
resolve(data.result);
if (callback != null) {
if (data.error) {
callback(data.error);
} else {
callback(undefined, data.result);
}
}
});
} catch (error) {
reject(error);
callback(error);
}
});
};
return callSend(jsonrpcPayload);
};
// Get the transaction Receipt, waiting until the receipt is ready.
// If it's a Privacy Marker Transaction then return the receipt for the inner private transaction.
const waitForTransactionReceipt = (txHash, retries = 300, delay = 1000) => {
const operation = () => {
return web3.eth.getTransactionReceipt(txHash);
};
return common
.waitForTransactionWithRetries(operation, txHash, retries, delay)
.then((receipt) => {
if (!receipt.isPrivacyMarkerTransaction) {
return receipt;
}
return web3.eth.getPrivateTransactionReceipt(txHash);
});
};
/**
* Submit a transaction.
* This method is similar to `web3.eth.sendTransaction()`, however it adds support for Privacy Marker Transactions.
* If the transaction is a Privacy Marker, then the promise will return the receipt for the inner private transaction,
* rather than the receipt for the Privacy Marker Transaction.
* Note that this method does not currently support `PromiEvent` events that are returned by `web3.eth.sendTransaction()`.
* @function sendGoQuorumTransaction
* @param {Object} transaction The transaction object to send (see `web3.eth.sendTransaction()` for object details)
* @param {Function} [callback] (optional) Optional callback, returns an error object as first parameter and the transaction hash as second.
* @returns {Promise<T>} Resolves when the transaction receipt is available.
*/
const sendGoQuorumTransaction = async (txnObject, callback) => {
const txHash = await sendTransactionUsingProvider(txnObject, callback);
return waitForTransactionReceipt(txHash);
};
Object.assign(web3.eth, {
sendGoQuorumTransaction,
});
return web3;
}
module.exports = Eth;