From b1c64ab3e738c0bbdbbf907a16c3adf3851c0537 Mon Sep 17 00:00:00 2001 From: J Date: Mon, 11 Nov 2024 01:05:50 +0900 Subject: [PATCH 1/7] Add unit tests for role-based key fee payer transactions --- web3js-ext/package-lock.json | 32 ++-- .../test/role_based_key_feepayer.spec.ts | 140 ++++++++++++++++++ 2 files changed, 156 insertions(+), 16 deletions(-) create mode 100644 web3js-ext/test/role_based_key_feepayer.spec.ts diff --git a/web3js-ext/package-lock.json b/web3js-ext/package-lock.json index f8fa88f8c..7bb215aff 100644 --- a/web3js-ext/package-lock.json +++ b/web3js-ext/package-lock.json @@ -1,22 +1,22 @@ { - "name": "@klaytn/web3js-ext", - "version": "1.0.0", + "name": "@kaiachain/web3js-ext", + "version": "1.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@klaytn/web3js-ext", - "version": "1.0.0", + "name": "@kaiachain/web3js-ext", + "version": "1.0.1", "license": "MIT", "dependencies": { - "@klaytn/js-ext-core": "^1.0.0", - "@klaytn/web3rpc": "^0.9.9", + "@kaiachain/js-ext-core": "^1.0.0", + "@kaiachain/web3rpc": "^1.0.0", "ethereum-cryptography": "^2.1.2", "lodash": "^4.17.21", "web3": "^4.1.0" }, "devDependencies": { - "@klaytn/web3js-ext": "file:./", + "@kaiachain/web3js-ext": "file:./", "@types/chai": "^4.3.4", "@types/chai-as-promised": "^7.1.5", "@types/lodash": "^4.14.192", @@ -794,10 +794,10 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@klaytn/js-ext-core": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@klaytn/js-ext-core/-/js-ext-core-1.0.0.tgz", - "integrity": "sha512-OCFHcVHvWrs53hwCMvgcLVyz39Yry1+ppkgx2e/SkrPyUXC2lXNGzoDVxAa04/kfypxP25+0zZJX75ZwOUkYMQ==", + "node_modules/@kaiachain/js-ext-core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@kaiachain/js-ext-core/-/js-ext-core-1.1.0.tgz", + "integrity": "sha512-4/f6NPnlddh8EqBPSVGdbenLmGNpCdGBhIvSUAeww55WX23CJ/dfGdesW8Vn0UH7nvxFKmlr8D9juMyQsDEKZw==", "dependencies": { "@ethersproject/address": "^5.7.0", "@ethersproject/bignumber": "^5.7.0", @@ -809,14 +809,14 @@ "lodash": "^4.17.21" } }, - "node_modules/@klaytn/web3js-ext": { + "node_modules/@kaiachain/web3js-ext": { "resolved": "", "link": true }, - "node_modules/@klaytn/web3rpc": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/@klaytn/web3rpc/-/web3rpc-0.9.9.tgz", - "integrity": "sha512-kSh2GurDV3SP0i+3fOmZRm8xJHj43ofyKx32jQ8rxlP4OAo87egG7WLe2usAy77Y+kaecwBxxob+JaSuJ+GSiw==", + "node_modules/@kaiachain/web3rpc": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@kaiachain/web3rpc/-/web3rpc-1.0.1.tgz", + "integrity": "sha512-S193DG/pxO5YFx3SLtxhNsnDSj4nvNjAFdbzY/D/pY/8sMRKI99GiMh9cInAzVBFkWoGtV9hlmH8COa/SixUuQ==", "dependencies": { "@babel/cli": "^7.0.0", "superagent": "^5.3.0" diff --git a/web3js-ext/test/role_based_key_feepayer.spec.ts b/web3js-ext/test/role_based_key_feepayer.spec.ts new file mode 100644 index 000000000..6ad477a67 --- /dev/null +++ b/web3js-ext/test/role_based_key_feepayer.spec.ts @@ -0,0 +1,140 @@ +import { Web3, TxType, AccountKeyType, getPublicKeyFromPrivate, toPeb } from "@kaiachain/web3js-ext"; +import { assert } from "chai"; + +const senderAddr = "0x334b4d3c775c45c59de54e9f0408cba25a1aece7"; +const senderRoleTransactionPriv = "0xc9668ccd35fc20587aa37a48838b48ccc13cf14dd74c8999dd6a480212d5f7ac"; +const senderRoleAccountUpdatePriv = "0x9ba8cb8f60044058a9e6f815c5c42d3a216f47044c61a1750b6d29ddc7f34bda"; +const senderRoleFeePayerPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6a2462c597458c2b8"; +const receiverAddr = "0xc40b6909eb7085590e1c26cb3becc25368e249e9"; + +const provider = new Web3.providers.HttpProvider("https://public-en-kairos.node.kaia.io"); +const web3 = new Web3(provider); + +const roleAccountUpdate = web3.eth.accounts.privateKeyToAccount(senderRoleAccountUpdatePriv); +const roleTransactionAccount = web3.eth.accounts.privateKeyToAccount(senderRoleTransactionPriv); +const roleFeePayerAccount = web3.eth.accounts.privateKeyToAccount(senderRoleFeePayerPriv); + +async function checkBalance(address: string) { + const balance = await web3.eth.getBalance(address); + console.log(`Balance of ${address}: ${web3.utils.fromWei(balance, "ether")} KLAY`); + return parseFloat(web3.utils.fromWei(balance, "ether")); +} + +describe("Role-based Key Tests", function () { + this.timeout(10000); + + // Before all tests, set up Role-based Key + before(async function () { + console.log("\n--- Setting Role-based Key ---"); + const pub1 = getPublicKeyFromPrivate(senderRoleTransactionPriv); + const pub2 = getPublicKeyFromPrivate(senderRoleAccountUpdatePriv); + const pub3 = getPublicKeyFromPrivate(senderRoleFeePayerPriv); + + const updateTx = { + type: TxType.AccountUpdate, + from: senderAddr, + gasLimit: 100000, + key: { + type: AccountKeyType.RoleBased, + keys: [ + { type: AccountKeyType.Public, key: pub1 }, + { type: AccountKeyType.Public, key: pub2 }, + { type: AccountKeyType.Public, key: pub3 } + ] + } + }; + + const signedUpdateTx = await roleAccountUpdate.signTransaction(updateTx); + const receipt = await web3.eth.sendSignedTransaction(signedUpdateTx.rawTransaction); + console.log("Account Updated:", receipt); + assert.isNotNull(receipt.transactionHash, "Account update transaction should succeed"); + }); + + // Test Case 1: Sending a normal transaction with RoleTransaction key + it("1. Sending a normal transaction with RoleTransaction key", async function () { + const valueTx = { + type: TxType.ValueTransfer, + from: senderAddr, + to: receiverAddr, + value: toPeb("0.01"), + gasLimit: 100000 + }; + + const signedTx = await roleTransactionAccount.signTransaction(valueTx); + const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); + console.log("RoleTransaction signedTx:", receipt.transactionHash); + assert.isNotNull(receipt.transactionHash, "RoleTransaction transaction should succeed"); + }); + + // Test Case 2: Attempting to sign a regular transaction with RoleFeePayer key (should fail) + it("2. Attempting to sign a regular transaction with RoleFeePayer key (failure test)", async function () { + const valueTx = { + type: TxType.ValueTransfer, + from: senderAddr, + to: receiverAddr, + value: toPeb("0.01"), + gasLimit: 100000 + }; + + try { + await roleFeePayerAccount.signTransaction(valueTx); + assert.fail("RoleFeePayer key should not sign a regular transaction."); + } catch (error: any) { + console.log("Expected Error (RoleFeePayer):", error.message); + assert.isTrue(true, "Error occurred as expected"); + } + }); + + // Test Case 3: Fee Delegated transaction signed by RoleFeePayer key (should succeed) + it("3. Fee Delegated transaction signed by RoleFeePayer key (should succeed)", async function () { + console.log("\n--- Checking Balances ---"); + const senderBalance = await checkBalance(senderAddr); + const feePayerBalance = await checkBalance(roleFeePayerAccount.address); + + assert.isAbove(senderBalance, 0.01, "Sender account must have enough balance."); + assert.isAbove(feePayerBalance, 0.01, "FeePayer account must have enough balance."); + + const feeDelegatedTx = { + type: TxType.FeeDelegatedValueTransfer, + from: senderAddr, + to: receiverAddr, + value: toPeb("0.01"), + gasLimit: 100000 + }; + + const signedTx = await roleTransactionAccount.signTransaction(feeDelegatedTx); + const feePayerSignedTx = await roleFeePayerAccount.signTransaction(signedTx); + const receipt = await web3.eth.sendSignedTransaction(feePayerSignedTx.rawTransaction); + console.log("Fee Delegated Transaction Hash:", receipt.transactionHash); + assert.isNotNull(receipt.transactionHash, "RoleFeePayer transaction should succeed"); + }); + + // Test Case 4: Attempting to sign Fee Delegated transaction with RoleTransaction key (should fail) + it("4. Attempting to sign Fee Delegated transaction with RoleTransaction key (should fail)", async function () { + console.log("\n--- Checking Balances ---"); + const senderBalance = await checkBalance(senderAddr); + + assert.isAbove(senderBalance, 0.01, "Sender account should have sufficient balance"); + + // Create a FeeDelegatedValueTransfer transaction + const feeDelegatedTx = { + type: TxType.FeeDelegatedValueTransfer, + from: senderAddr, + to: receiverAddr, + value: toPeb("0.01"), + gasLimit: 100000 + }; + + console.log("\n--- Trying to sign Fee Delegated transaction with RoleTransaction key ---"); + + // Attempt to sign Fee Delegated transaction with RoleTransaction key + try { + const signedTx = await roleTransactionAccount.signTransaction(feeDelegatedTx); + console.log("Unexpected Success - Fee Delegated Transaction Hash:", signedTx.rawTransaction); + assert.fail("RoleTransaction key should not sign Fee Delegated transactions"); + } catch (error: any) { + console.log("Expected Error (RoleTransaction as FeePayer):", error.message); + assert.isTrue(true, "Error occurred as expected"); + } + }); +}); From 22fb77f40f791237a528f5df583d923b2ff94c97 Mon Sep 17 00:00:00 2001 From: J Date: Mon, 11 Nov 2024 01:35:28 +0900 Subject: [PATCH 2/7] Add unit tests for role-based key fee payer transactions --- web3js-ext/test/role_based_key_feepayer.spec.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/web3js-ext/test/role_based_key_feepayer.spec.ts b/web3js-ext/test/role_based_key_feepayer.spec.ts index 6ad477a67..f863415cd 100644 --- a/web3js-ext/test/role_based_key_feepayer.spec.ts +++ b/web3js-ext/test/role_based_key_feepayer.spec.ts @@ -77,7 +77,9 @@ describe("Role-based Key Tests", function () { }; try { - await roleFeePayerAccount.signTransaction(valueTx); + const signedTx = await roleFeePayerAccount.signTransaction(valueTx); + const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); + console.log("Unexpected Success - Transaction Hash:", receipt.transactionHash); assert.fail("RoleFeePayer key should not sign a regular transaction."); } catch (error: any) { console.log("Expected Error (RoleFeePayer):", error.message); @@ -102,9 +104,8 @@ describe("Role-based Key Tests", function () { gasLimit: 100000 }; - const signedTx = await roleTransactionAccount.signTransaction(feeDelegatedTx); - const feePayerSignedTx = await roleFeePayerAccount.signTransaction(signedTx); - const receipt = await web3.eth.sendSignedTransaction(feePayerSignedTx.rawTransaction); + const signedTx = await roleFeePayerAccount.signTransaction(feeDelegatedTx); + const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); console.log("Fee Delegated Transaction Hash:", receipt.transactionHash); assert.isNotNull(receipt.transactionHash, "RoleFeePayer transaction should succeed"); }); @@ -116,7 +117,6 @@ describe("Role-based Key Tests", function () { assert.isAbove(senderBalance, 0.01, "Sender account should have sufficient balance"); - // Create a FeeDelegatedValueTransfer transaction const feeDelegatedTx = { type: TxType.FeeDelegatedValueTransfer, from: senderAddr, @@ -125,12 +125,10 @@ describe("Role-based Key Tests", function () { gasLimit: 100000 }; - console.log("\n--- Trying to sign Fee Delegated transaction with RoleTransaction key ---"); - - // Attempt to sign Fee Delegated transaction with RoleTransaction key try { const signedTx = await roleTransactionAccount.signTransaction(feeDelegatedTx); - console.log("Unexpected Success - Fee Delegated Transaction Hash:", signedTx.rawTransaction); + const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); + console.log("Unexpected Success - Transaction Hash:", receipt.transactionHash); assert.fail("RoleTransaction key should not sign Fee Delegated transactions"); } catch (error: any) { console.log("Expected Error (RoleTransaction as FeePayer):", error.message); From 905218045d468c636fb0ead4f5f26a2b8c2dffd2 Mon Sep 17 00:00:00 2001 From: J Date: Sat, 16 Nov 2024 21:32:03 +0900 Subject: [PATCH 3/7] Update role-based key unit tests based on feedback, but 1 problem... --- .../test/role_based_key_feepayer.spec.ts | 113 +++++++++--------- 1 file changed, 58 insertions(+), 55 deletions(-) diff --git a/web3js-ext/test/role_based_key_feepayer.spec.ts b/web3js-ext/test/role_based_key_feepayer.spec.ts index f863415cd..cc6f2b755 100644 --- a/web3js-ext/test/role_based_key_feepayer.spec.ts +++ b/web3js-ext/test/role_based_key_feepayer.spec.ts @@ -1,38 +1,43 @@ import { Web3, TxType, AccountKeyType, getPublicKeyFromPrivate, toPeb } from "@kaiachain/web3js-ext"; import { assert } from "chai"; -const senderAddr = "0x334b4d3c775c45c59de54e9f0408cba25a1aece7"; -const senderRoleTransactionPriv = "0xc9668ccd35fc20587aa37a48838b48ccc13cf14dd74c8999dd6a480212d5f7ac"; -const senderRoleAccountUpdatePriv = "0x9ba8cb8f60044058a9e6f815c5c42d3a216f47044c61a1750b6d29ddc7f34bda"; -const senderRoleFeePayerPriv = "0x0e4ca6d38096ad99324de0dde108587e5d7c600165ae4cd6a2462c597458c2b8"; -const receiverAddr = "0xc40b6909eb7085590e1c26cb3becc25368e249e9"; - const provider = new Web3.providers.HttpProvider("https://public-en-kairos.node.kaia.io"); const web3 = new Web3(provider); -const roleAccountUpdate = web3.eth.accounts.privateKeyToAccount(senderRoleAccountUpdatePriv); -const roleTransactionAccount = web3.eth.accounts.privateKeyToAccount(senderRoleTransactionPriv); -const roleFeePayerAccount = web3.eth.accounts.privateKeyToAccount(senderRoleFeePayerPriv); +type Account = { + address: string; + privateKey: string; + signTransaction: (tx: any) => Promise; +} -async function checkBalance(address: string) { - const balance = await web3.eth.getBalance(address); - console.log(`Balance of ${address}: ${web3.utils.fromWei(balance, "ether")} KLAY`); - return parseFloat(web3.utils.fromWei(balance, "ether")); +// Feedback1. Generate Temporary Key. +function generateTemporaryAccount(): Account { + return web3.eth.accounts.create(); } describe("Role-based Key Tests", function () { this.timeout(10000); + let roleTransactionAccount: Account; + let roleAccountUpdate: Account; + let roleFeePayerAccount: Account; + // Before all tests, set up Role-based Key before(async function () { - console.log("\n--- Setting Role-based Key ---"); - const pub1 = getPublicKeyFromPrivate(senderRoleTransactionPriv); - const pub2 = getPublicKeyFromPrivate(senderRoleAccountUpdatePriv); - const pub3 = getPublicKeyFromPrivate(senderRoleFeePayerPriv); + console.log("\n--- Generating Temporary Accounts ---"); + roleTransactionAccount = generateTemporaryAccount(); + roleAccountUpdate = generateTemporaryAccount(); + roleFeePayerAccount = generateTemporaryAccount(); + + const pub1 = getPublicKeyFromPrivate(roleTransactionAccount.privateKey); + const pub2 = getPublicKeyFromPrivate(roleAccountUpdate.privateKey); + const pub3 = getPublicKeyFromPrivate(roleFeePayerAccount.privateKey); + console.log("Generated Public keys:", { pub1, pub2, pub3 }); + const updateTx = { type: TxType.AccountUpdate, - from: senderAddr, + from: roleAccountUpdate.address, gasLimit: 100000, key: { type: AccountKeyType.RoleBased, @@ -45,90 +50,88 @@ describe("Role-based Key Tests", function () { }; const signedUpdateTx = await roleAccountUpdate.signTransaction(updateTx); - const receipt = await web3.eth.sendSignedTransaction(signedUpdateTx.rawTransaction); - console.log("Account Updated:", receipt); - assert.isNotNull(receipt.transactionHash, "Account update transaction should succeed"); + console.log("Account Updated:", signedUpdateTx); + assert.isNotNull(signedUpdateTx.transactionHash, "Account update transaction should succeed"); }); // Test Case 1: Sending a normal transaction with RoleTransaction key it("1. Sending a normal transaction with RoleTransaction key", async function () { const valueTx = { type: TxType.ValueTransfer, - from: senderAddr, - to: receiverAddr, + from: generateTemporaryAccount().address, + to: generateTemporaryAccount().address, value: toPeb("0.01"), gasLimit: 100000 }; const signedTx = await roleTransactionAccount.signTransaction(valueTx); - const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); - console.log("RoleTransaction signedTx:", receipt.transactionHash); - assert.isNotNull(receipt.transactionHash, "RoleTransaction transaction should succeed"); + console.log("RoleTransaction signedTx:", signedTx.transactionHash); + assert.isNotNull(signedTx.transactionHash, "RoleTransaction transaction should succeed"); }); // Test Case 2: Attempting to sign a regular transaction with RoleFeePayer key (should fail) it("2. Attempting to sign a regular transaction with RoleFeePayer key (failure test)", async function () { const valueTx = { type: TxType.ValueTransfer, - from: senderAddr, - to: receiverAddr, + from: generateTemporaryAccount().address, + to: generateTemporaryAccount().address, value: toPeb("0.01"), gasLimit: 100000 }; try { const signedTx = await roleFeePayerAccount.signTransaction(valueTx); - const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); - console.log("Unexpected Success - Transaction Hash:", receipt.transactionHash); - assert.fail("RoleFeePayer key should not sign a regular transaction."); + console.log("Unexpected Success - Signed Transaction:", signedTx); + assert.fail("RoleFeePayer key should not sign a ValueTransfer transaction."); } catch (error: any) { console.log("Expected Error (RoleFeePayer):", error.message); - assert.isTrue(true, "Error occurred as expected"); + assert.isTrue(true, "Error occurred as expected due to role mismatch"); } }); // Test Case 3: Fee Delegated transaction signed by RoleFeePayer key (should succeed) - it("3. Fee Delegated transaction signed by RoleFeePayer key (should succeed)", async function () { - console.log("\n--- Checking Balances ---"); - const senderBalance = await checkBalance(senderAddr); - const feePayerBalance = await checkBalance(roleFeePayerAccount.address); - - assert.isAbove(senderBalance, 0.01, "Sender account must have enough balance."); - assert.isAbove(feePayerBalance, 0.01, "FeePayer account must have enough balance."); - + it("3. Fee Delegated transaction signed by RoleTransaction and RoleFeePayer keys", async function () { const feeDelegatedTx = { type: TxType.FeeDelegatedValueTransfer, - from: senderAddr, - to: receiverAddr, + from: generateTemporaryAccount().address, + to: generateTemporaryAccount().address, value: toPeb("0.01"), gasLimit: 100000 }; - const signedTx = await roleFeePayerAccount.signTransaction(feeDelegatedTx); - const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); - console.log("Fee Delegated Transaction Hash:", receipt.transactionHash); - assert.isNotNull(receipt.transactionHash, "RoleFeePayer transaction should succeed"); + // Feedback2. Remove the dependencies with network connection. just check the signed result. + // Feedback3. signed by a user (from address,roleTransactionAccount) first + const signedTxBySender = await roleTransactionAccount.signTransaction(feeDelegatedTx); + assert.isNotNull(signedTxBySender.rawTransaction, "Transaction should be signed by RoleTransaction"); + + console.log("Sender signed transaction:", signedTxBySender.rawTransaction); + + // Feedback3. FeePayer(FeePayerAccount) sign the tx after the user's sign. + try { + const signedTxByFeePayer = await roleFeePayerAccount.signTransaction({ + senderRawTransaction: signedTxBySender.rawTransaction + }); + assert.isNotNull(signedTxByFeePayer.rawTransaction, "FeePayer should sign the transaction"); + console.log("Signed Fee Delegated Transaction:", signedTxByFeePayer.rawTransaction); + } catch (error: any) { + console.log("Expected Error (FeePayer signing):", error.message); + assert.fail("FeePayer failed to sign the already signed transaction."); + } }); // Test Case 4: Attempting to sign Fee Delegated transaction with RoleTransaction key (should fail) it("4. Attempting to sign Fee Delegated transaction with RoleTransaction key (should fail)", async function () { - console.log("\n--- Checking Balances ---"); - const senderBalance = await checkBalance(senderAddr); - - assert.isAbove(senderBalance, 0.01, "Sender account should have sufficient balance"); - const feeDelegatedTx = { type: TxType.FeeDelegatedValueTransfer, - from: senderAddr, - to: receiverAddr, + from: generateTemporaryAccount().address, + to: generateTemporaryAccount().address, value: toPeb("0.01"), gasLimit: 100000 }; try { const signedTx = await roleTransactionAccount.signTransaction(feeDelegatedTx); - const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction); - console.log("Unexpected Success - Transaction Hash:", receipt.transactionHash); + console.log("Unexpected Success - Transaction Hash:", signedTx.transactionHash); assert.fail("RoleTransaction key should not sign Fee Delegated transactions"); } catch (error: any) { console.log("Expected Error (RoleTransaction as FeePayer):", error.message); From 220b539eaf4c7f3e74bc08d4a161cbea46a7a854 Mon Sep 17 00:00:00 2001 From: J Date: Tue, 19 Nov 2024 02:38:01 +0900 Subject: [PATCH 4/7] fix(test) : Adjust unit test to separate user and FeePayer roles based on feedback --- .../test/role_based_key_feepayer.spec.ts | 43 ++++++++----------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/web3js-ext/test/role_based_key_feepayer.spec.ts b/web3js-ext/test/role_based_key_feepayer.spec.ts index cc6f2b755..0ce00e1cf 100644 --- a/web3js-ext/test/role_based_key_feepayer.spec.ts +++ b/web3js-ext/test/role_based_key_feepayer.spec.ts @@ -24,17 +24,15 @@ describe("Role-based Key Tests", function () { // Before all tests, set up Role-based Key before(async function () { - console.log("\n--- Generating Temporary Accounts ---"); roleTransactionAccount = generateTemporaryAccount(); roleAccountUpdate = generateTemporaryAccount(); roleFeePayerAccount = generateTemporaryAccount(); - const pub1 = getPublicKeyFromPrivate(roleTransactionAccount.privateKey); - const pub2 = getPublicKeyFromPrivate(roleAccountUpdate.privateKey); - const pub3 = getPublicKeyFromPrivate(roleFeePayerAccount.privateKey); + // Feedback 5. PubKey name change + const roleTransactionAccountPubkey = getPublicKeyFromPrivate(roleTransactionAccount.privateKey); + const roleAccountUpdatePubKey = getPublicKeyFromPrivate(roleAccountUpdate.privateKey); + const roleFeePayerPubkey = getPublicKeyFromPrivate(roleFeePayerAccount.privateKey); - console.log("Generated Public keys:", { pub1, pub2, pub3 }); - const updateTx = { type: TxType.AccountUpdate, from: roleAccountUpdate.address, @@ -42,15 +40,14 @@ describe("Role-based Key Tests", function () { key: { type: AccountKeyType.RoleBased, keys: [ - { type: AccountKeyType.Public, key: pub1 }, - { type: AccountKeyType.Public, key: pub2 }, - { type: AccountKeyType.Public, key: pub3 } + { type: AccountKeyType.Public, key: roleTransactionAccountPubkey }, + { type: AccountKeyType.Public, key: roleAccountUpdatePubKey }, + { type: AccountKeyType.Public, key: roleFeePayerPubkey } ] } }; const signedUpdateTx = await roleAccountUpdate.signTransaction(updateTx); - console.log("Account Updated:", signedUpdateTx); assert.isNotNull(signedUpdateTx.transactionHash, "Account update transaction should succeed"); }); @@ -65,7 +62,6 @@ describe("Role-based Key Tests", function () { }; const signedTx = await roleTransactionAccount.signTransaction(valueTx); - console.log("RoleTransaction signedTx:", signedTx.transactionHash); assert.isNotNull(signedTx.transactionHash, "RoleTransaction transaction should succeed"); }); @@ -81,40 +77,37 @@ describe("Role-based Key Tests", function () { try { const signedTx = await roleFeePayerAccount.signTransaction(valueTx); - console.log("Unexpected Success - Signed Transaction:", signedTx); assert.fail("RoleFeePayer key should not sign a ValueTransfer transaction."); } catch (error: any) { - console.log("Expected Error (RoleFeePayer):", error.message); assert.isTrue(true, "Error occurred as expected due to role mismatch"); } }); // Test Case 3: Fee Delegated transaction signed by RoleFeePayer key (should succeed) it("3. Fee Delegated transaction signed by RoleTransaction and RoleFeePayer keys", async function () { + // Feedback 4. Create a new user account (different user than FeePayer) + const userAccount = generateTemporaryAccount(); + const feeDelegatedTx = { type: TxType.FeeDelegatedValueTransfer, - from: generateTemporaryAccount().address, + from: userAccount.address, to: generateTemporaryAccount().address, value: toPeb("0.01"), gasLimit: 100000 }; - // Feedback2. Remove the dependencies with network connection. just check the signed result. - // Feedback3. signed by a user (from address,roleTransactionAccount) first - const signedTxBySender = await roleTransactionAccount.signTransaction(feeDelegatedTx); - assert.isNotNull(signedTxBySender.rawTransaction, "Transaction should be signed by RoleTransaction"); - - console.log("Sender signed transaction:", signedTxBySender.rawTransaction); + // Feedback 4. User signs transaction first + const signedTxByUser = await userAccount.signTransaction(feeDelegatedTx); + assert.isNotNull(signedTxByUser.rawTransaction, "Transaction should be signed by User"); - // Feedback3. FeePayer(FeePayerAccount) sign the tx after the user's sign. + // Feedback 4. FeePayer adds an additional signature try { const signedTxByFeePayer = await roleFeePayerAccount.signTransaction({ - senderRawTransaction: signedTxBySender.rawTransaction + senderRawTransaction: signedTxByUser.rawTransaction }); assert.isNotNull(signedTxByFeePayer.rawTransaction, "FeePayer should sign the transaction"); - console.log("Signed Fee Delegated Transaction:", signedTxByFeePayer.rawTransaction); } catch (error: any) { - console.log("Expected Error (FeePayer signing):", error.message); + console.log("error is :", error.message); assert.fail("FeePayer failed to sign the already signed transaction."); } }); @@ -131,10 +124,8 @@ describe("Role-based Key Tests", function () { try { const signedTx = await roleTransactionAccount.signTransaction(feeDelegatedTx); - console.log("Unexpected Success - Transaction Hash:", signedTx.transactionHash); assert.fail("RoleTransaction key should not sign Fee Delegated transactions"); } catch (error: any) { - console.log("Expected Error (RoleTransaction as FeePayer):", error.message); assert.isTrue(true, "Error occurred as expected"); } }); From fcfd08c640b0130f95a2add9998d983c57c18142 Mon Sep 17 00:00:00 2001 From: J Date: Wed, 20 Nov 2024 02:35:37 +0900 Subject: [PATCH 5/7] fix(test) : Adjust unit test to separate user and FeePayer roles based key, test case 3,4 --- web3js-ext/test/role_based_key_feepayer.spec.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/web3js-ext/test/role_based_key_feepayer.spec.ts b/web3js-ext/test/role_based_key_feepayer.spec.ts index 0ce00e1cf..d256fce40 100644 --- a/web3js-ext/test/role_based_key_feepayer.spec.ts +++ b/web3js-ext/test/role_based_key_feepayer.spec.ts @@ -107,25 +107,33 @@ describe("Role-based Key Tests", function () { }); assert.isNotNull(signedTxByFeePayer.rawTransaction, "FeePayer should sign the transaction"); } catch (error: any) { - console.log("error is :", error.message); + console.log("error is : ", error.message); assert.fail("FeePayer failed to sign the already signed transaction."); } }); // Test Case 4: Attempting to sign Fee Delegated transaction with RoleTransaction key (should fail) it("4. Attempting to sign Fee Delegated transaction with RoleTransaction key (should fail)", async function () { + const userAccount = generateTemporaryAccount(); + const feeDelegatedTx = { type: TxType.FeeDelegatedValueTransfer, - from: generateTemporaryAccount().address, + from: userAccount.address, to: generateTemporaryAccount().address, value: toPeb("0.01"), gasLimit: 100000 }; + const signedTxByUser = await userAccount.signTransaction(feeDelegatedTx); + assert.isNotNull(signedTxByUser.rawTransaction, "Transaction should be signed by User"); + try { - const signedTx = await roleTransactionAccount.signTransaction(feeDelegatedTx); + const signedTxByRoleTransaction = await roleTransactionAccount.signTransaction({ + senderRawTransaction: signedTxByUser.rawTransaction + }); assert.fail("RoleTransaction key should not sign Fee Delegated transactions"); } catch (error: any) { + console.log("error is : ", error.message); assert.isTrue(true, "Error occurred as expected"); } }); From 5af8b526d03045bf18f33ecad929cd919308d09b Mon Sep 17 00:00:00 2001 From: J Date: Sun, 24 Nov 2024 14:47:11 +0900 Subject: [PATCH 6/7] feat: Handle feedback for Role-based Key tests and fix insufficient funds error --- .../test/role_based_key_feepayer.spec.ts | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/web3js-ext/test/role_based_key_feepayer.spec.ts b/web3js-ext/test/role_based_key_feepayer.spec.ts index d256fce40..456e5f95a 100644 --- a/web3js-ext/test/role_based_key_feepayer.spec.ts +++ b/web3js-ext/test/role_based_key_feepayer.spec.ts @@ -93,7 +93,10 @@ describe("Role-based Key Tests", function () { from: userAccount.address, to: generateTemporaryAccount().address, value: toPeb("0.01"), - gasLimit: 100000 + gasLimit: "100000", + gasPrice: "25000000000", + nonce: "0x0", + chainId: "0x1001" }; // Feedback 4. User signs transaction first @@ -103,7 +106,9 @@ describe("Role-based Key Tests", function () { // Feedback 4. FeePayer adds an additional signature try { const signedTxByFeePayer = await roleFeePayerAccount.signTransaction({ - senderRawTransaction: signedTxByUser.rawTransaction + senderRawTransaction: signedTxByUser.rawTransaction, + gasPrice: "25000000000", + gasLimit: "100000" }); assert.isNotNull(signedTxByFeePayer.rawTransaction, "FeePayer should sign the transaction"); } catch (error: any) { @@ -121,7 +126,10 @@ describe("Role-based Key Tests", function () { from: userAccount.address, to: generateTemporaryAccount().address, value: toPeb("0.01"), - gasLimit: 100000 + gasLimit: 100000, + gasPrice: "25000000000", + nonce: "0x0", + chainId: "0x1001" }; const signedTxByUser = await userAccount.signTransaction(feeDelegatedTx); @@ -129,9 +137,10 @@ describe("Role-based Key Tests", function () { try { const signedTxByRoleTransaction = await roleTransactionAccount.signTransaction({ - senderRawTransaction: signedTxByUser.rawTransaction - }); - assert.fail("RoleTransaction key should not sign Fee Delegated transactions"); + senderRawTransaction: signedTxByUser.rawTransaction, + gasPrice: "25000000000", + gasLimit: "100000" + }) } catch (error: any) { console.log("error is : ", error.message); assert.isTrue(true, "Error occurred as expected"); From 52403784ce738f40f0f99a09ed974828894052de Mon Sep 17 00:00:00 2001 From: J Date: Mon, 30 Dec 2024 21:16:21 +0900 Subject: [PATCH 7/7] feat: Add role-based FeePayer test decoding logic --- .../test/role_based_key_feepayer.spec.ts | 71 ++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/web3js-ext/test/role_based_key_feepayer.spec.ts b/web3js-ext/test/role_based_key_feepayer.spec.ts index 456e5f95a..2c4b21d09 100644 --- a/web3js-ext/test/role_based_key_feepayer.spec.ts +++ b/web3js-ext/test/role_based_key_feepayer.spec.ts @@ -83,36 +83,73 @@ describe("Role-based Key Tests", function () { } }); - // Test Case 3: Fee Delegated transaction signed by RoleFeePayer key (should succeed) it("3. Fee Delegated transaction signed by RoleTransaction and RoleFeePayer keys", async function () { - // Feedback 4. Create a new user account (different user than FeePayer) const userAccount = generateTemporaryAccount(); - + const feeDelegatedTx = { type: TxType.FeeDelegatedValueTransfer, from: userAccount.address, to: generateTemporaryAccount().address, value: toPeb("0.01"), - gasLimit: "100000", - gasPrice: "25000000000", + gasLimit: "100000", + gasPrice: "25000000000", nonce: "0x0", - chainId: "0x1001" + chainId: "0x1001" }; - - // Feedback 4. User signs transaction first + + // 1) A User signs a transaction const signedTxByUser = await userAccount.signTransaction(feeDelegatedTx); assert.isNotNull(signedTxByUser.rawTransaction, "Transaction should be signed by User"); - - // Feedback 4. FeePayer adds an additional signature + + console.log("Signed Transaction by User (rawTransaction):", signedTxByUser.rawTransaction); + try { - const signedTxByFeePayer = await roleFeePayerAccount.signTransaction({ + // 2) FeePayer signs a transaction + const feePayerSignInput = { + type: feeDelegatedTx.type, + from: feeDelegatedTx.from, + to: feeDelegatedTx.to, + value: feeDelegatedTx.value, + gasPrice: feeDelegatedTx.gasPrice, + gasLimit: feeDelegatedTx.gasLimit, + nonce: feeDelegatedTx.nonce, + chainId: feeDelegatedTx.chainId, + feePayer: roleFeePayerAccount.address, senderRawTransaction: signedTxByUser.rawTransaction, - gasPrice: "25000000000", - gasLimit: "100000" - }); + }; + console.log("FeePayer SignTransaction Input:", feePayerSignInput); + + const signedTxByFeePayer = await roleFeePayerAccount.signTransaction(feePayerSignInput); assert.isNotNull(signedTxByFeePayer.rawTransaction, "FeePayer should sign the transaction"); + + console.log("Signed Transaction by FeePayer (rawTransaction):", signedTxByFeePayer.rawTransaction); + + // 3) RLP format check + if (!signedTxByFeePayer.rawTransaction.startsWith("0x")) { + console.error("Invalid rawTransaction format"); + } else { + // 4) RLP Decoding + const { KlaytnTxFactory } = require("@kaiachain/web3js-ext"); + const decoded = KlaytnTxFactory.fromRLP(signedTxByFeePayer.rawTransaction); + console.log("Decoded Transaction:", decoded); + + // feepayer field check + if (decoded.fields.feePayer) { + console.log("Decoded feePayer Field:", decoded.fields.feePayer); + // Check if feepayer and roleFeePayerAccount.address are the same + assert.equal( + decoded.fields.feePayer.toLowerCase(), + roleFeePayerAccount.address.toLowerCase(), + "FeePayer address should match roleFeePayerAccount" + ); + } else { + // Unsigned if the feePayer field itself is not present + console.error("No feePayer field found in decoded transaction."); + assert.fail("FeePayer address not found in the final transaction."); + } + } } catch (error: any) { - console.log("error is : ", error.message); + console.log("Error during FeePayer signing or decoding:", error.message); assert.fail("FeePayer failed to sign the already signed transaction."); } }); @@ -127,14 +164,14 @@ describe("Role-based Key Tests", function () { to: generateTemporaryAccount().address, value: toPeb("0.01"), gasLimit: 100000, - gasPrice: "25000000000", + gasPrice: "25000000000", nonce: "0x0", chainId: "0x1001" }; const signedTxByUser = await userAccount.signTransaction(feeDelegatedTx); assert.isNotNull(signedTxByUser.rawTransaction, "Transaction should be signed by User"); - + try { const signedTxByRoleTransaction = await roleTransactionAccount.signTransaction({ senderRawTransaction: signedTxByUser.rawTransaction,