status-desktop/storybook/qmlTests/tests/tst_SignRequestPlugin.qml

268 lines
19 KiB
QML
Raw Normal View History

import QtQuick 2.15
import QtTest 1.15
import AppLayouts.Wallet.services.dapps 1.0
import AppLayouts.Wallet.services.dapps.plugins 1.0
import AppLayouts.Wallet.services.dapps.types 1.0
import shared.stores 1.0
import utils 1.0
Item {
id: root
Component {
id: signRequestPluginComponent
SignRequestPlugin {
id: plugin
property SignalSpy acceptedSpy: SignalSpy { target: plugin; signalName: "accepted" }
property SignalSpy rejectedSpy: SignalSpy { target: plugin; signalName: "rejected" }
property SignalSpy signCompletedSpy: SignalSpy { target: plugin; signalName: "signCompleted" }
sdk: WalletConnectSDKBase {
id: sdk
enabled: true
projectId: ""
property bool sdkReady: true
property var getActiveSessionsCallbacks: []
getActiveSessions: function(callback) {
getActiveSessionsCallbacks.push({callback})
}
property var acceptSessionRequestCalls: []
acceptSessionRequest: function(topic, id, signature) {
acceptSessionRequestCalls.push({topic, id, signature})
}
property var rejectSessionRequestCalls: []
rejectSessionRequest: function(topic, id, error) {
rejectSessionRequestCalls.push({topic, id, error})
}
}
store: DAppsStore {
id: dappsStore
signal userAuthenticated(string topic, string id, string password, string pin, string payload)
signal userAuthenticationFailed(string topic, string id)
signal signingResult(string topic, string id, string data)
function hexToDec(hex) {
return parseInt(hex, 16)
}
function getEstimatedTime() {
return Constants.TransactionEstimatedTime.LessThanThreeMins
}
function convertFeesInfoToHex(feesInfo) {
return null
}
property var mockedSuggestedFees: ({
gasPrice: 2.0,
baseFee: 5.0,
maxPriorityFeePerGas: 2.0,
maxFeePerGasL: 1.0,
maxFeePerGasM: 1.1,
maxFeePerGasH: 1.2,
l1GasFee: 0.0,
eip1559Enabled: true
})
function getSuggestedFees() {
return mockedSuggestedFees
}
property var authenticateUserCalls: []
function authenticateUser(topic, id, address) {
authenticateUserCalls.push({topic, id, address})
}
property var signMessageCalls: []
function signMessage(topic, id, address, message, password, pin) {
signMessageCalls.push({topic, id, address, password, pin})
}
property var signMessageUnsafeCalls: []
function signMessageUnsafe(topic, id, address, data, password, pin) {
signMessageUnsafeCalls.push({topic, id, address, data, password, pin})
}
property var safeSignTypedDataCalls: []
function safeSignTypedData(topic, id, address, message, chainId, legacy, password, pin) {
safeSignTypedDataCalls.push({topic, id, address, message, chainId, legacy, password, pin})
}
property var signTransactionCalls: []
function signTransaction(topic, id, address, chainId, txObj, password, pin) {
signTransactionCalls.push({topic, id, address, chainId, txObj, password, pin})
}
property var sendTransactionCalls: []
function sendTransaction(topic, id, address, chainID, txObj, password, pin) {
sendTransactionCalls.push({topic, id, address, chainID, txObj, password, pin})
}
}
dappsModel: ListModel {
id: dappsModel
}
groupedAccountAssetsModel: ListModel {
id: groupedAccountAssetsModel
}
networksModel: ListModel {
id: networksModel
ListElement {
chainId: 1
layer: 1
}
}
accountsModel: ListModel {
id: accountsModel
ListElement {
address: "0x123"
}
}
currentCurrency: "USD"
requests: SessionRequestsModel {}
getFiatValue: (balance, cryptoSymbol) => {
return parseFloat(balance)
}
}
}
TestCase {
id: signRequestPluginTest
property SignRequestPlugin componentUnderTest: null
function populateDAppData(topic) {
const dapp = {
topic,
name: "Example",
url: "https://example.com",
iconUrl: "https://example.com/icon.png",
connectorId: 0,
accountAddresses: [{address: "0x123"}],
rawSessions: [{session: {topic}}]
}
componentUnderTest.dappsModel.append(dapp)
}
function executeRequest(signEvent) {
populateDAppData(signEvent.topic)
componentUnderTest.sdk.sessionRequestEvent(signEvent)
// Execute the request
const request = componentUnderTest.requests.get(0)
request.requestItem.execute("passowrd", "pin")
componentUnderTest.store.signingResult(signEvent.topic, signEvent.id, "result")
compare(componentUnderTest.sdk.acceptSessionRequestCalls.length, 1, "Accept session request should be called")
compare(componentUnderTest.sdk.acceptSessionRequestCalls[0].signature, "result", "Accept session request should be called with the correct signature")
compare(componentUnderTest.sdk.acceptSessionRequestCalls[0].topic.toString(), signEvent.topic.toString(), "Accept session request should be called with the correct topic")
compare(componentUnderTest.sdk.acceptSessionRequestCalls[0].id.toString(), signEvent.id.toString(), "Accept session request should be called with the correct id")
compare(componentUnderTest.acceptedSpy.count, 1, "Accepted signal should be emitted")
}
function init() {
componentUnderTest = createTemporaryObject(signRequestPluginComponent, root)
}
function test_signMessage() {
const signEvent = {"id":1730896110928724,"params":{"chainId":"eip155:1","request":{"method":"personal_sign","params":["0x4578616d706c652060706572736f6e616c5f7369676e60206d657373616765","0x123","Example password"]}},"topic":"43a74a4c6c71e3ab67ef80283dc43f392445642c8dce3dabe63f89ab83cfcfc3","verifyContext":{"verified":{"origin":"https://metamask.github.io/test-dapp/","validation":"UNKNOWN","verifyUrl":"https://verify.walletconnect.org"}}}
// Case 1: DApp not found
ignoreWarning(`Error finding dapp for topic ${signEvent.topic} id ${signEvent.id}`)
componentUnderTest.sdk.sessionRequestEvent(signEvent)
compare(componentUnderTest.sdk.rejectSessionRequestCalls.length, 1, "Reject session request should not be called")
// Case 2: DApp found
executeRequest(signEvent)
compare(componentUnderTest.store.signMessageCalls.length, 1, "Sign message should be called")
componentUnderTest.sdk.sessionRequestUserAnswerResult(signEvent.topic, signEvent.id, true, null)
const requestItem = componentUnderTest.requests.get(0).requestItem
compare(requestItem.requestId, signEvent.id.toString(), "Request id should be set")
compare(requestItem.topic, signEvent.topic.toString(), "Topic should be set")
compare(requestItem.method, signEvent.params.request.method, "Method should be set")
compare(requestItem.accountAddress, signEvent.params.request.params[1], "Account address should be set")
compare(requestItem.chainId, signEvent.params.chainId.split(':').pop().trim(), "Chain id should be set")
compare(requestItem.sourceId, componentUnderTest.dappsModel.get(0).connectorId, "Source id should be set")
compare(componentUnderTest.signCompletedSpy.count, 1, "Sign completed signal should be emitted")
}
function test_signMessageUnsafe() {
const signEvent = {"id":1730896224189361,"params":{"chainId":"eip155:1","request":{"method":"eth_sign","params":["0x123","0x123"]}},"topic":"43a74a4c6c71e3ab67ef80283dc43f392445642c8dce3dabe63f89ab83cfcfc3","verifyContext":{"verified":{"origin":"https://metamask.github.io/test-dapp/","validation":"UNKNOWN","verifyUrl":"https://verify.walletconnect.org"}}}
executeRequest(signEvent)
compare(componentUnderTest.store.signMessageUnsafeCalls.length, 1, "Sign message unsafe should be called")
componentUnderTest.sdk.sessionRequestUserAnswerResult(signEvent.topic, signEvent.id, true, null)
compare(componentUnderTest.signCompletedSpy.count, 1, "Sign completed signal should be emitted")
}
function test_safeSignTypedData() {
const signEvent = {"id":1730896495619543,"params":{"chainId":"eip155:1","request":{"method":"eth_signTypedData_v4","params":["0x123","{\"domain\":{\"chainId\":\"1\",\"name\":\"Ether Mail\",\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\",\"version\":\"1\"},\"message\":{\"contents\":\"Hello, Bob!\",\"from\":{\"name\":\"Cow\",\"wallets\":[\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\"]},\"to\":[{\"name\":\"Bob\",\"wallets\":[\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\",\"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57\",\"0xB0B0b0b0b0b0B000000000000000000000000000\"]}],\"attachment\":\"0x\"},\"primaryType\":\"Mail\",\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Group\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"members\",\"type\":\"Person[]\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person[]\"},{\"name\":\"contents\",\"type\":\"string\"},{\"name\":\"attachment\",\"type\":\"bytes\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallets\",\"type\":\"address[]\"}]}}"]}},"topic":"43a74a4c6c71e3ab67ef80283dc43f392445642c8dce3dabe63f89ab83cfcfc3","verifyContext":{"verified":{"origin":"https://metamask.github.io/test-dapp/","validation":"UNKNOWN","verifyUrl":"https://verify.walletconnect.org"}}}
executeRequest(signEvent)
compare(componentUnderTest.store.safeSignTypedDataCalls.length, 1, "Safe sign typed data should be called")
componentUnderTest.sdk.sessionRequestUserAnswerResult(signEvent.topic, signEvent.id, true, null)
compare(componentUnderTest.signCompletedSpy.count, 1, "Sign completed signal should be emitted")
}
function test_sendTransaction() {
const signEvent = {"id":1730899979094571,"params":{"chainId":"eip155:1","request":{"method":"eth_sendTransaction","params":[{"from":"0x123","gasLimit":"0x5028","maxFeePerGas":"0x2540be400","maxPriorityFeePerGas":"0x3b9aca00","to":"0x0c54FcCd2e384b4BB6f2E405Bf5Cbc15a017AaFb","value":"0x0"}]}},"topic":"147fa9ddffcf9d782b5e002eb36b041e43a1db2bad79a598da6926105ce6680f","verifyContext":{"verified":{"origin":"https://metamask.github.io/test-dapp/","validation":"UNKNOWN","verifyUrl":"https://verify.walletconnect.org"}}}
executeRequest(signEvent)
compare(componentUnderTest.store.sendTransactionCalls.length, 1, "Send transaction should be called")
componentUnderTest.sdk.sessionRequestUserAnswerResult(signEvent.topic, signEvent.id, true, null)
compare(componentUnderTest.signCompletedSpy.count, 1, "Sign completed signal should be emitted")
}
function reject_sign() {
const signEvent = {"id":1730896495619543,"params":{"chainId":"eip155:1","request":{"method":"eth_signTypedData_v4","params":["0x123","{\"domain\":{\"chainId\":\"1\",\"name\":\"Ether Mail\",\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\",\"version\":\"1\"},\"message\":{\"contents\":\"Hello, Bob!\",\"from\":{\"name\":\"Cow\",\"wallets\":[\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\"]},\"to\":[{\"name\":\"Bob\",\"wallets\":[\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\",\"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57\",\"0xB0B0b0b0b0b0B000000000000000000000000000\"]}],\"attachment\":\"0x\"},\"primaryType\":\"Mail\",\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Group\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"members\",\"type\":\"Person[]\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person[]\"},{\"name\":\"contents\",\"type\":\"string\"},{\"name\":\"attachment\",\"type\":\"bytes\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallets\",\"type\":\"address[]\"}]}}"]}},"topic":"43a74a4c6c71e3ab67ef80283dc43f392445642c8dce3dabe63f89ab83cfcfc3","verifyContext":{"verified":{"origin":"https://metamask.github.io/test-dapp/","validation":"UNKNOWN","verifyUrl":"https://verify.walletconnect.org"}}}
populateDAppData(signEvent.topic)
componentUnderTest.sdk.sessionRequestEvent(signEvent)
// Execute the request
const request = componentUnderTest.requests.get(0)
request.requestItem.rejected(false)
compare(componentUnderTest.sdk.rejectSessionRequestCalls.length, 1, "Reject session request should be called")
compare(componentUnderTest.rejectedSpy.count, 1, "Rejected signal should be emitted")
compare(componentUnderTest.signCompletedSpy.count, 0, "Sign completed signal should not be emitted")
}
function test_authFailed() {
const signEvent = {"id":1730896495619543,"params":{"chainId":"eip155:1","request":{"method":"eth_signTypedData_v4","params":["0x123","{\"domain\":{\"chainId\":\"1\",\"name\":\"Ether Mail\",\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\",\"version\":\"1\"},\"message\":{\"contents\":\"Hello, Bob!\",\"from\":{\"name\":\"Cow\",\"wallets\":[\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\"]},\"to\":[{\"name\":\"Bob\",\"wallets\":[\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\",\"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57\",\"0xB0B0b0b0b0b0B000000000000000000000000000\"]}],\"attachment\":\"0x\"},\"primaryType\":\"Mail\",\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Group\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"members\",\"type\":\"Person[]\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person[]\"},{\"name\":\"contents\",\"type\":\"string\"},{\"name\":\"attachment\",\"type\":\"bytes\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallets\",\"type\":\"address[]\"}]}}"]}},"topic":"43a74a4c6c71e3ab67ef80283dc43f392445642c8dce3dabe63f89ab83cfcfc3","verifyContext":{"verified":{"origin":"https://metamask.github.io/test-dapp/","validation":"UNKNOWN","verifyUrl":"https://verify.walletconnect.org"}}}
populateDAppData(signEvent.topic)
componentUnderTest.sdk.sessionRequestEvent(signEvent)
// Execute the request
const request = componentUnderTest.requests.get(0)
request.requestItem.authFailed()
compare(componentUnderTest.sdk.rejectSessionRequestCalls.length, 1, "Reject session request should be called")
compare(componentUnderTest.rejectedSpy.count, 1, "Rejected signal should be emitted")
compare(componentUnderTest.signCompletedSpy.count, 0, "Sign completed signal should not be emitted")
}
function test_signMessageFails() {
const signEvent = {"id":1730896495619543,"params":{"chainId":"eip155:1","request":{"method":"eth_signTypedData_v4","params":["0x123","{\"domain\":{\"chainId\":\"1\",\"name\":\"Ether Mail\",\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\",\"version\":\"1\"},\"message\":{\"contents\":\"Hello, Bob!\",\"from\":{\"name\":\"Cow\",\"wallets\":[\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\",\"0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF\"]},\"to\":[{\"name\":\"Bob\",\"wallets\":[\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\",\"0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57\",\"0xB0B0b0b0b0b0B000000000000000000000000000\"]}],\"attachment\":\"0x\"},\"primaryType\":\"Mail\",\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Group\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"members\",\"type\":\"Person[]\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person[]\"},{\"name\":\"contents\",\"type\":\"string\"},{\"name\":\"attachment\",\"type\":\"bytes\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallets\",\"type\":\"address[]\"}]}}"]}},"topic":"43a74a4c6c71e3ab67ef80283dc43f392445642c8dce3dabe63f89ab83cfcfc3","verifyContext":{"verified":{"origin":"https://metamask.github.io/test-dapp/","validation":"UNKNOWN","verifyUrl":"https://verify.walletconnect.org"}}}
populateDAppData(signEvent.topic)
componentUnderTest.sdk.sessionRequestEvent(signEvent)
// Execute the request
const request = componentUnderTest.requests.get(0)
request.requestItem.execute("passowrd", "pin")
componentUnderTest.store.signingResult(signEvent.topic, signEvent.id, "")
compare(componentUnderTest.sdk.rejectSessionRequestCalls.length, 1, "Reject session request should be called")
compare(componentUnderTest.rejectedSpy.count, 1, "Rejected signal should be emitted")
compare(componentUnderTest.signCompletedSpy.count, 0, "Sign completed signal should not be emitted")
}
}
}