Skip to content

Commit

Permalink
feat(cactus-plugin-ledger-connector-ethereum): add signing utils
Browse files Browse the repository at this point in the history
- Add methods for signing transactions to ethereum connector.
- Modify offline signing test to use this new method.
- Modify electricity trade sample to use new signing method.
- Add offline signature section to ethereum connector readme.

Signed-off-by: Michal Bajer <[email protected]>
  • Loading branch information
outSH committed Oct 6, 2023
1 parent 9e66850 commit fd9c571
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export class BusinessLogicElectricityTrade extends BusinessLogicBase {
{
to: accountInfo["toAddress"],
value: Number(transactionSubset["Value"]),
gas: config.electricityTradeInfo.ethereum.gas,
gasLimit: config.electricityTradeInfo.ethereum.gas,
},
accountInfo["fromAddress"],
accountInfo["fromAddressPkey"],
Expand Down
18 changes: 12 additions & 6 deletions examples/cactus-example-electricity-trade/TransactionEthereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
* transaction-ethereum.ts
*/

import { ConfigUtil } from "@hyperledger/cactus-cmd-socketio-server";
import {
ConfigUtil,
TransactionSigner,
} from "@hyperledger/cactus-cmd-socketio-server";
import { Web3SigningCredentialType } from "@hyperledger/cactus-plugin-ledger-connector-ethereum";
Web3SigningCredentialType,
signTransaction,
} from "@hyperledger/cactus-plugin-ledger-connector-ethereum";

const config: any = ConfigUtil.getConfig();
import { getLogger } from "log4js";
Expand Down Expand Up @@ -37,9 +37,15 @@ export async function sendEthereumTransaction(
}
logger.debug("sendEthereumTransaction", transaction);

const { serializedTx, txId } = TransactionSigner.signTxEthereum(
const { serializedTransactionHex, txId } = signTransaction(
transaction,
privateKey,
{
name: config.signTxInfo.ethereum.chainName,
chainId: config.signTxInfo.ethereum.chainID,
networkId: config.signTxInfo.ethereum.networkID,
defaultHardfork: config.signTxInfo.ethereum.defaultHardfork,
},
);
logger.info("Sending ethereum transaction with ID", txId);

Expand All @@ -48,7 +54,7 @@ export async function sendEthereumTransaction(
type: Web3SigningCredentialType.None,
},
transactionConfig: {
rawTransaction: serializedTx,
rawTransaction: serializedTransactionHex,
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ blpRegistry:

logLevel: debug

signTxInfo:
ethereum:
chainName: geth1
networkID: 10
chainID: 10
defaultHardfork: petersburg

appRouters:
-
path: /api/v1/bl/electricity-trade/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,3 @@ ledgerPluginInfo:
ledgerInfo:
ledgerAbstract: Sawtooth Ledger
apiInfo: []

signTxInfo:
ethereum:
chainName: geth1
networkID: 10
chainID: 10
network: mainnet
hardfork: petersburg
34 changes: 34 additions & 0 deletions packages/cactus-plugin-ledger-connector-ethereum/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,40 @@ args: {
},
```
### Offline signing utils
- Use `signTransaction` from this package to sign transactions payload locally (outside of connector process).
- Offline signed transaction can be send with `Web3SigningCredentialType.None` signing credetnial type in runTransactionV1 endpoint.
``` typescript
// Offline sign transaction
const { serializedTransactionHex } = signTransaction(
{
to: anotherAccount,
value: 10e6,
maxPriorityFeePerGas: 0,
maxFeePerGas: 0x40000000,
gasLimit: 21000,
type: 2
},
myPrivateKey,
{
networkId: 10,
chainId: 10,
defaultHardfork: "london",
},
);

// Send transaction payload to connector
await apiClient.runTransactionV1({
web3SigningCredential: {
type: Web3SigningCredentialType.None,
},
transactionConfig: {
rawTransaction: serializedTransactionHex,
},
});
```
## Running the tests
To check that all has been installed correctly and that the pugin has no errors run jest test suites.
Expand Down
2 changes: 2 additions & 0 deletions packages/cactus-plugin-ledger-connector-ethereum/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
"webpack:dev:web": "webpack --env=dev --target=web --config ../../webpack.config.js"
},
"dependencies": {
"@ethereumjs/common": "4.0.0",
"@ethereumjs/tx": "5.0.0",
"@hyperledger/cactus-common": "2.0.0-alpha.2",
"@hyperledger/cactus-core": "2.0.0-alpha.2",
"@hyperledger/cactus-core-api": "2.0.0-alpha.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export {
IPluginLedgerConnectorEthereumOptions,
} from "./plugin-ledger-connector-ethereum";

export * from "./sign-utils";

export * from "./types/model-type-guards";

export { PluginFactoryLedgerConnector } from "./plugin-factory-ledger-connector";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Chain, Common } from "@ethereumjs/common";
import {
AccessListEIP2930Transaction,
BlobEIP4844Transaction,
FeeMarketEIP1559Transaction,
LegacyTransaction,
TransactionFactory,
TypedTxData,
} from "@ethereumjs/tx";

type CustomChainArg = Parameters<typeof Common.custom>[0];

/**
* Sign ethereum transaction data offline. Can be used with both mainnet and custom chains.
*
* @param txData transaction data (format must be compatible with @ethereumjs/tx)
* @param privateKey HEX private signing key
* @param customChainInfo optional custom chain information (default: mainnet)
*
* @returns serialized transaction, txId (hash) and signedTransaction object
*/
export function signTransaction(
txData: TypedTxData,
privateKey: string,
customChainInfo?: CustomChainArg,
): {
serializedTransactionHex: string;
txId: string;
signedTransactionObject:
| LegacyTransaction
| AccessListEIP2930Transaction
| FeeMarketEIP1559Transaction
| BlobEIP4844Transaction;
} {
let chainConfiguration = new Common({ chain: Chain.Mainnet });
if (customChainInfo) {
chainConfiguration = Common.custom(customChainInfo);
}

const transaction = TransactionFactory.fromTxData(txData, {
common: chainConfiguration,
});
if (privateKey.toLowerCase().startsWith("0x")) {
privateKey = privateKey.slice(2);
}
const signedTransaction = transaction.sign(Buffer.from(privateKey, "hex"));

const hash = signedTransaction.hash();
const txId = "0x" + Buffer.from(hash).toString("hex");
const serializedTransaction = signedTransaction.serialize();
const serializedTransactionHex =
"0x" + Buffer.from(serializedTransaction).toString("hex");

return {
serializedTransactionHex,
txId,
signedTransactionObject: signedTransaction,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import {
DeployContractSolidityBytecodeV1Request,
RunTransactionRequest,
InvokeContractV1Request,
signTransaction,
} from "../../../main/typescript/public-api";
import { K_CACTUS_ETHEREUM_TOTAL_TX_COUNT } from "../../../main/typescript/prometheus-exporter/metrics";

Expand Down Expand Up @@ -336,28 +337,33 @@ describe("Ethereum contract deploy and invoke using keychain tests", () => {
expect(invokeGetNameOut.data.callOutput).toBe(newName);
});

test("invoke Web3SigningCredentialType.NONE", async () => {
test("invoke Web3SigningCredentialType.None", async () => {
const testEthAccount2 = web3.eth.accounts.create();

const value = 10e6;
const { rawTransaction } = await web3.eth.accounts.signTransaction(
const { serializedTransactionHex } = signTransaction(
{
from: testEthAccount.address,
to: testEthAccount2.address,
value,
maxPriorityFeePerGas: 0,
maxFeePerGas: 0x40000000,
gasLimit: 21000,
type: 2
},
testEthAccount.privateKey,
{
networkId: 10,
chainId: 10,
defaultHardfork: "london",
},
);

await apiClient.runTransactionV1({
web3SigningCredential: {
type: Web3SigningCredentialType.None,
},
transactionConfig: {
rawTransaction,
rawTransaction: serializedTransactionHex,
},
});

Expand Down
Loading

0 comments on commit fd9c571

Please sign in to comment.