-
Notifications
You must be signed in to change notification settings - Fork 19
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
fix: make e2e tests for passkey more rigorous in their success checks #2246
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,18 +1,14 @@ | ||
import '@frequency-chain/api-augment'; | ||
import assert from 'assert'; | ||
import { | ||
createAndFundKeypair, | ||
EcdsaSignature, | ||
getBlockNumber, | ||
getNonce, | ||
Sr25519Signature, | ||
} from '../scaffolding/helpers'; | ||
import { createAndFundKeypair, EcdsaSignature, getNonce, Sr25519Signature } from '../scaffolding/helpers'; | ||
import { KeyringPair } from '@polkadot/keyring/types'; | ||
import { ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; | ||
import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers'; | ||
import { getFundingSource } from '../scaffolding/funding'; | ||
import { getUnifiedPublicKey, getUnifiedAddress } from '../scaffolding/ethereum'; | ||
import { createPassKeyAndSignAccount, createPassKeyCallV2, createPasskeyPayloadV2 } from '../scaffolding/P256'; | ||
import { u8aToHex, u8aWrapBytes } from '@polkadot/util'; | ||
import { AccountId32 } from '@polkadot/types/interfaces'; | ||
import { ISubmittableResult } from '@polkadot/types/types'; | ||
const fundingSource = getFundingSource(import.meta.url); | ||
|
||
describe('Passkey Pallet Proxy V2 Ethereum Tests', function () { | ||
|
@@ -28,11 +24,13 @@ describe('Passkey Pallet Proxy V2 Ethereum Tests', function () { | |
}); | ||
|
||
it('should transfer via passkeys with root sr25519 key into an ethereum style account', async function () { | ||
const startingBalance = (await ExtrinsicHelper.getAccountInfo(receiverKeys)).data.free.toBigInt(); | ||
const accountPKey = getUnifiedPublicKey(fundedSr25519Keys); | ||
const nonce = await getNonce(fundedSr25519Keys); | ||
const transferAmount = 55_000_000n; | ||
const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive( | ||
getUnifiedAddress(receiverKeys), | ||
55_000_000n | ||
transferAmount | ||
); | ||
const { passKeyPrivateKey, passKeyPublicKey } = createPassKeyAndSignAccount(accountPKey); | ||
const accountSignature = fundedSr25519Keys.sign(u8aWrapBytes(passKeyPublicKey)); | ||
|
@@ -46,42 +44,154 @@ describe('Passkey Pallet Proxy V2 Ethereum Tests', function () { | |
false | ||
); | ||
const passkeyProxy = ExtrinsicHelper.executePassKeyProxyV2(fundedSr25519Keys, passkeyPayload); | ||
await assert.doesNotReject(passkeyProxy.fundAndSendUnsigned(fundingSource)); | ||
await ExtrinsicHelper.waitForFinalization((await getBlockNumber()) + 2); | ||
// adding some delay before fetching the nonce to ensure it is updated | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); | ||
Comment on lines
-49
to
-52
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 don't need to await finalization now that |
||
try { | ||
const { | ||
target, | ||
eventMap: { 'balances.Transfer': transferEvent }, | ||
} = await passkeyProxy.fundAndSendUnsigned(fundingSource); | ||
assert.notEqual(target, undefined, 'Target event should not be undefined'); | ||
assert.equal( | ||
ExtrinsicHelper.api.events.balances.Transfer.is(transferEvent), | ||
true, | ||
'Transfer event should be of correct type' | ||
); | ||
if (transferEvent && ExtrinsicHelper.api.events.balances.Transfer.is(transferEvent)) { | ||
const { from, to, amount } = transferEvent.data; | ||
assert.equal( | ||
from.toString(), | ||
getUnifiedAddress(fundedSr25519Keys), | ||
'From address should be the funded sr25519 key' | ||
); | ||
assert.equal(to.toString(), getUnifiedAddress(receiverKeys), 'To address should be the receiver key'); | ||
assert.equal(amount.toBigInt(), transferAmount, `Transfer amount should be ${transferAmount}`); | ||
} | ||
} catch (e: any) { | ||
assert.fail(e); | ||
} | ||
|
||
/* | ||
* Normally these checks would be unnecessary, but we are testing the passkey pallet | ||
* which has additional logic surrounding mapping account keys, so we want to make sure | ||
* that the nonce and balance are updated correctly. | ||
*/ | ||
const nonceAfter = (await ExtrinsicHelper.getAccountInfo(fundedSr25519Keys)).nonce.toNumber(); | ||
assert.equal(nonce + 1, nonceAfter); | ||
}); | ||
assert.equal(nonce + 1, nonceAfter, 'Nonce should be incremented by 1'); | ||
|
||
it('should transfer via passkeys with root ethereum style key into another one', async function () { | ||
const accountPKey = getUnifiedPublicKey(fundedEthereumKeys); | ||
console.log(`accountPKey ${u8aToHex(accountPKey)}`); | ||
const nonce = await getNonce(fundedEthereumKeys); | ||
const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive( | ||
getUnifiedAddress(receiverKeys), | ||
66_000_000n | ||
const balanceAfter = (await ExtrinsicHelper.getAccountInfo(receiverKeys)).data.free.toBigInt(); | ||
assert.equal( | ||
balanceAfter, | ||
startingBalance + transferAmount, | ||
'Receiver balance should be incremented by transfer amount' | ||
); | ||
const { passKeyPrivateKey, passKeyPublicKey } = createPassKeyAndSignAccount(accountPKey); | ||
// ethereum keys should not have wrapping | ||
const accountSignature = fundedEthereumKeys.sign(passKeyPublicKey); | ||
console.log(`accountSignature ${u8aToHex(accountSignature)}`); | ||
const multiSignature: EcdsaSignature = { Ecdsa: u8aToHex(accountSignature) }; | ||
const passkeyCall = await createPassKeyCallV2(accountPKey, nonce, transferCalls); | ||
const passkeyPayload = await createPasskeyPayloadV2( | ||
multiSignature, | ||
passKeyPrivateKey, | ||
passKeyPublicKey, | ||
passkeyCall, | ||
false | ||
); | ||
const passkeyProxy = ExtrinsicHelper.executePassKeyProxyV2(fundingSource, passkeyPayload); | ||
await assert.doesNotReject(passkeyProxy.sendUnsigned()); | ||
await ExtrinsicHelper.waitForFinalization((await getBlockNumber()) + 2); | ||
// adding some delay before fetching the nonce to ensure it is updated | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); | ||
const nonceAfter = (await ExtrinsicHelper.getAccountInfo(fundedEthereumKeys)).nonce.toNumber(); | ||
assert.equal(nonce + 1, nonceAfter); | ||
}); | ||
|
||
describe('successful transfer via passkeys with root ethereum-style key into a polkadot-style key', function () { | ||
let startingReceiverBalance: bigint; | ||
let startingSenderBalance: bigint; | ||
let accountPKey: Uint8Array<ArrayBufferLike>; | ||
let nonce: number; | ||
let target: any; | ||
let transferEvent: any; | ||
let feeEvent: any; | ||
let passkeyProxy: Extrinsic< | ||
{ | ||
accountId: AccountId32; | ||
}, | ||
ISubmittableResult, | ||
[accountId: AccountId32] | ||
>; | ||
|
||
const transferAmount = 66_000_000n; | ||
|
||
before(async function () { | ||
startingReceiverBalance = (await ExtrinsicHelper.getAccountInfo(receiverKeys)).data.free.toBigInt(); | ||
startingSenderBalance = (await ExtrinsicHelper.getAccountInfo(fundedEthereumKeys)).data.free.toBigInt(); | ||
accountPKey = getUnifiedPublicKey(fundedEthereumKeys); | ||
console.log(`accountPKey ${u8aToHex(accountPKey)}`); | ||
nonce = await getNonce(fundedEthereumKeys); | ||
const transferCalls = ExtrinsicHelper.api.tx.balances.transferKeepAlive( | ||
getUnifiedAddress(receiverKeys), | ||
transferAmount | ||
); | ||
const { passKeyPrivateKey, passKeyPublicKey } = createPassKeyAndSignAccount(accountPKey); | ||
// ethereum keys should not have wrapping | ||
const accountSignature = fundedEthereumKeys.sign(passKeyPublicKey); | ||
console.log(`accountSignature ${u8aToHex(accountSignature)}`); | ||
const multiSignature: EcdsaSignature = { Ecdsa: u8aToHex(accountSignature) }; | ||
const passkeyCall = await createPassKeyCallV2(accountPKey, nonce, transferCalls); | ||
const passkeyPayload = await createPasskeyPayloadV2( | ||
multiSignature, | ||
passKeyPrivateKey, | ||
passKeyPublicKey, | ||
passkeyCall, | ||
false | ||
); | ||
passkeyProxy = ExtrinsicHelper.executePassKeyProxyV2(fundingSource, passkeyPayload); | ||
}); | ||
|
||
it('should successfully execute transfer extrinsic', async function () { | ||
await assert.doesNotReject(async () => { | ||
({ | ||
target, | ||
eventMap: { 'balances.Transfer': transferEvent, 'balances.Withdraw': feeEvent }, | ||
} = await passkeyProxy.sendUnsigned()); | ||
}); | ||
}); | ||
|
||
it('should have received a transaction execution success event', async function () { | ||
assert.notEqual(target, undefined, 'Target event should not be undefined'); | ||
assert.equal( | ||
ExtrinsicHelper.api.events.passkey.TransactionExecutionSuccess.is(target), | ||
true, | ||
'Target event should be of correct type' | ||
); | ||
}); | ||
|
||
it('should have debited & credited correct accounts for the correct amount', async function () { | ||
if (transferEvent && ExtrinsicHelper.api.events.balances.Transfer.is(transferEvent)) { | ||
const { from, to, amount } = transferEvent.data; | ||
assert.equal(from.toString(), getUnifiedAddress(fundedEthereumKeys), 'From address should be the funded key'); | ||
assert.equal(to.toString(), getUnifiedAddress(receiverKeys), 'To address should be the receiver key'); | ||
assert.equal(amount.toBigInt(), transferAmount, `Transfer amount should be ${transferAmount}`); | ||
} else { | ||
assert.fail('Transfer event not found'); | ||
} | ||
}); | ||
|
||
it('should have deducted fee from the sender', async function () { | ||
if (feeEvent && ExtrinsicHelper.api.events.balances.Withdraw.is(feeEvent)) { | ||
const { who, amount } = feeEvent.data; | ||
assert.equal(who.toString(), getUnifiedAddress(fundedEthereumKeys), 'Fee should be deducted from the sender'); | ||
assert.equal(amount.toBigInt() > 0, true, 'Fee should be greater than 0'); | ||
} else { | ||
assert.fail('Fee event not found'); | ||
} | ||
}); | ||
|
||
/* | ||
* Normally these checks would be unnecessary, but we are testing the passkey pallet | ||
* which has additional logic surrounding mapping account keys, so we want to make sure | ||
* that the nonce and balance are updated correctly. | ||
*/ | ||
it('should have incremented nonce by 1 for sender', async function () { | ||
const nonceAfter = (await ExtrinsicHelper.getAccountInfo(fundedEthereumKeys)).nonce.toNumber(); | ||
assert.equal(nonce + 1, nonceAfter, 'Nonce should be incremented by 1'); | ||
}); | ||
|
||
it('should have changed account balances correctly', async function () { | ||
const endingReceiverBalance = (await ExtrinsicHelper.getAccountInfo(receiverKeys)).data.free.toBigInt(); | ||
const endingSenderBalance = (await ExtrinsicHelper.getAccountInfo(fundedEthereumKeys)).data.free.toBigInt(); | ||
assert.equal( | ||
endingReceiverBalance, | ||
startingReceiverBalance + transferAmount, | ||
'Receiver balance should be incremented by transfer amount' | ||
); | ||
assert.equal( | ||
startingSenderBalance - transferAmount >= endingSenderBalance, | ||
true, | ||
'Sender balance should be decremented by at least transfer amount' | ||
); | ||
}); | ||
}); | ||
}); | ||
}); |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Do we have constants for these like DOLLARS and CENTS?
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.
Not sure, but the amount isn't important anyway; we just want to be sure to check that whatever amount is transferred, the balance changes by that amount.
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.
But that does remind me, it would be good to also check that the correct sender's balance decreases by the appropriate amount.