Skip to content
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

test: added E2E coverage for isAuthorizedRaw() in HIP-632. #997

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,25 @@
"name": "HbarAllowance",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "account",
"type": "address"
},
{
"indexed": false,
"internalType": "bool",
"name": "response",
"type": "bool"
}
],
"name": "IsAuthorizedRaw",
"type": "event"
},
{
"anonymous": false,
"inputs": [
Expand Down Expand Up @@ -218,6 +237,40 @@
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "account",
"type": "address"
},
{
"internalType": "bytes",
"name": "messageHash",
"type": "bytes"
},
{
"internalType": "bytes",
"name": "signature",
"type": "bytes"
}
],
"name": "isAuthorizedRawPublic",
"outputs": [
{
"internalType": "int64",
"name": "responseCode",
"type": "int64"
},
{
"internalType": "bool",
"name": "response",
"type": "bool"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,13 @@ abstract contract HederaAccountService {
/// @param account The account to check the signature against
/// @param messageHash The hash of the message to check the signature against
/// @param signature The signature to check
/// @return responseCode The response code for the status of the request. SUCCESS is 22.
/// @return response True if the signature is valid, false otherwise
function isAuthorizedRaw(address account, bytes memory messageHash, bytes memory signature) internal returns (bool response) {
function isAuthorizedRaw(address account, bytes memory messageHash, bytes memory signature) internal returns (int64 responseCode, bool response) {
(bool success, bytes memory result) = HASPrecompileAddress.call(
abi.encodeWithSelector(IHederaAccountService.isAuthorizedRaw.selector,
account, messageHash, signature));
response = success ? abi.decode(result, (bool)) : false;
(responseCode, response) = success ? (HederaResponseCodes.SUCCESS, abi.decode(result, (bool))) : (HederaResponseCodes.UNKNOWN, false);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import "../../../hedera-token-service/HederaTokenService.sol";
contract CryptoAllowance is HederaAccountService, HederaTokenService {
event ResponseCode(int responseCode);
event HbarAllowance(address owner, address spender, int256 allowance);
event IsAuthorizedRaw(address account, bool response);

function hbarApprovePublic(address owner, address spender, int256 amount) public returns (int64 responseCode) {
responseCode = HederaAccountService.hbarApprove(owner, spender, amount);
Expand All @@ -26,6 +27,15 @@ contract CryptoAllowance is HederaAccountService, HederaTokenService {
emit HbarAllowance(owner, spender, allowance);
}

function isAuthorizedRawPublic(address account, bytes memory messageHash, bytes memory signature) public returns (int64 responseCode, bool response) {
(responseCode, response) = HederaAccountService.isAuthorizedRaw(account, messageHash, signature);
emit ResponseCode(responseCode);
if (responseCode != HederaResponseCodes.SUCCESS) {
revert("mehehehehe");
}
emit IsAuthorizedRaw(account, response);
}

function cryptoTransferPublic(IHederaTokenService.TransferList calldata transferList, IHederaTokenService.TokenTransferList[] calldata tokenTransferList) public returns (int responseCode) {
responseCode = HederaTokenService.cryptoTransfer(transferList, tokenTransferList);
emit ResponseCode(responseCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ const Constants = require('../../../constants');
const {
pollForNewSignerBalanceUsingProvider,
} = require('../../../../utils/helpers');
const {
Hbar,
PrivateKey,
AccountCreateTransaction,
} = require('@hashgraph/sdk');

describe('@CryptoAllowance Test Suite', () => {
let walletA,
Expand Down Expand Up @@ -302,4 +307,144 @@ describe('@CryptoAllowance Test Suite', () => {
expect(e.code).to.eq(Constants.CALL_EXCEPTION);
}
});

describe(`isAuthorizedRaw`, () => {
const messageToSign = 'Hedera Account Service';
const messageHashEC = ethers.hashMessage(messageToSign);
const messageHashED = Buffer.from(messageToSign);
const EDItems = [];

before(async () => {
for (let i = 0; i < 2; i++) {
const newEdPK = PrivateKey.generateED25519();
const newEdPubKey = newEdPK.publicKey;
const client = await Utils.createSDKClient();

const edSignerAccount = (
await (
await new AccountCreateTransaction()
.setKey(newEdPubKey)
.setInitialBalance(Hbar.fromTinybars(1000))
.execute(client)
).getReceipt(client)
).accountId;
const signerAlias = `0x${edSignerAccount.toSolidityAddress()}`;
const signature = `0x${Buffer.from(newEdPK.sign(messageHashED)).toString('hex')}`;

const obj = {
signature,
signerAlias,
};

EDItems.push(obj);
}
});

it('Should verify message signature and return TRUE using isAuthorizedRawPublic for ECDSA account', async () => {
const signature = await walletB.signMessage(messageToSign);
expect(signature.slice(2).length).to.eq(65 * 2); // 65 bytes ECDSA signature

const correctSignerReceipt = await (
await cryptoAllowanceContract.isAuthorizedRawPublic(
walletB.address, // correct signer
messageHashEC,
signature,
Constants.GAS_LIMIT_1_000_000
)
).wait();

const correctSignerReceiptResponseCode = correctSignerReceipt.logs.find(
(l) => l.fragment.name === 'ResponseCode'
).args[0];

const correctSignerReceiptResponse = correctSignerReceipt.logs.find(
(l) => l.fragment.name === 'IsAuthorizedRaw'
).args;

expect(correctSignerReceiptResponseCode).to.eq(22n);
expect(correctSignerReceiptResponse[0]).to.eq(walletB.address);
expect(correctSignerReceiptResponse[1]).to.be.true;
});

it('Should verify message signature and return FALSE using isAuthorizedRawPublic for ECDSA account', async () => {
const signature = await walletB.signMessage(messageToSign);
expect(signature.slice(2).length).to.eq(65 * 2); // 65 bytes ECDSA signature

const incorrectSignerReceipt = await (
await cryptoAllowanceContract.isAuthorizedRawPublic(
walletC.address, // incorrect signer
messageHashEC,
signature,
Constants.GAS_LIMIT_1_000_000
)
).wait();

const incorrectSignerReceiptResponseCode =
incorrectSignerReceipt.logs.find(
(l) => l.fragment.name === 'ResponseCode'
).args[0];

const incorrectSignerReceiptResponse = incorrectSignerReceipt.logs.find(
(l) => l.fragment.name === 'IsAuthorizedRaw'
).args;

expect(incorrectSignerReceiptResponseCode).to.eq(22n);
expect(incorrectSignerReceiptResponse[0]).to.eq(walletC.address);
expect(incorrectSignerReceiptResponse[1]).to.be.false;
});

it('Should verify message signature and return TRUE using isAuthorizedRawPublic for ED25519 account', async () => {
const correctSignerReceipt = await (
await cryptoAllowanceContract.isAuthorizedRawPublic(
EDItems[0].signerAlias, // correct alias
messageHashED,
EDItems[0].signature, // correct signature
Constants.GAS_LIMIT_10_000_000
)
).wait();

const correctSignerReceiptResponseCode = correctSignerReceipt.logs.find(
(l) => l.fragment.name === 'ResponseCode'
).args[0];

const correctSignerReceiptResponse = correctSignerReceipt.logs.find(
(l) => l.fragment.name === 'IsAuthorizedRaw'
).args;

expect(correctSignerReceiptResponseCode).to.eq(22n);
expect(correctSignerReceiptResponse[0].toLowerCase()).to.eq(
EDItems[0].signerAlias.toLowerCase()
);
expect(correctSignerReceiptResponse[1]).to.be.true;
});

it('Should verify message signature and return FALSE using isAuthorizedRawPublic for ED25519 account', async () => {
const incorrectSignerReceipt = await (
await cryptoAllowanceContract.isAuthorizedRawPublic(
EDItems[0].signerAlias, // incorrect signer
messageHashED,
EDItems[1].signature, // different signature
Constants.GAS_LIMIT_10_000_000
)
).wait();

const incorrectSignerReceiptResponseCode =
incorrectSignerReceipt.logs.find(
(l) => l.fragment.name === 'ResponseCode'
).args[0];

const incorrectSignerReceiptResponse = incorrectSignerReceipt.logs.find(
(l) => l.fragment.name === 'IsAuthorizedRaw'
).args;

expect(incorrectSignerReceiptResponseCode).to.eq(22n);
expect(incorrectSignerReceiptResponse[0].toLowerCase()).to.eq(
EDItems[0].signerAlias.toLowerCase()
);
expect(incorrectSignerReceiptResponse[0].toLowerCase()).to.not.eq(
EDItems[1].signerAlias.toLowerCase()
);
expect(incorrectSignerReceiptResponse[1]).to.be.false;
});
});
quiet-node marked this conversation as resolved.
Show resolved Hide resolved
});
Loading