feat(WalletConnect): Implement sign request modal (#15520)
* feat(WalletConnect): Implement sign request modal 1. Implementing sign request modal based on SignTransactionModalBase 2. Adding storybook page 3. Integrate it in the app 4. Removing DAppRequestModal 5. Update RoundImageWithBadge to preserve aspect ratio between badge and main image * fix(WalletConnect): Remove unneeded properties from WalletConnectService API Removing `selectedAccountAddress` and `loginType`. These properties are now passed through DAppsWorkflow API * fix(WalletConnect): Removing unnecessary changes
This commit is contained in:
parent
2a41622298
commit
ca8a0028a8
|
@ -1,196 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml 2.15
|
||||
import Qt.labs.settings 1.0
|
||||
import QtTest 1.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Utils 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Popups.Dialog 0.1
|
||||
|
||||
import Models 1.0
|
||||
import Storybook 1.0
|
||||
|
||||
import shared.popups.walletconnect 1.0
|
||||
|
||||
import SortFilterProxyModel 0.2
|
||||
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
import AppLayouts.Wallet.services.dapps.types 1.0
|
||||
|
||||
import utils 1.0
|
||||
import shared.stores 1.0
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
function openModal() {
|
||||
modal.open()
|
||||
}
|
||||
|
||||
// qml Splitter
|
||||
SplitView {
|
||||
anchors.fill: parent
|
||||
|
||||
ColumnLayout {
|
||||
SplitView.fillWidth: true
|
||||
|
||||
Component.onCompleted: root.openModal()
|
||||
|
||||
DAppRequestModal {
|
||||
id: modal
|
||||
|
||||
anchors.centerIn: parent
|
||||
|
||||
spacing: 8
|
||||
|
||||
dappName: settings.dappName
|
||||
dappUrl: settings.dappUrl
|
||||
dappIcon: settings.dappIcon
|
||||
payloadData: d.currentPayload ? d.currentPayload.payloadData : null
|
||||
method: d.currentPayload ? d.currentPayload.method : ""
|
||||
maxFeesText: d.currentPayload ? d.currentPayload.maxFeesText : ""
|
||||
maxFeesEthText: d.currentPayload ? d.currentPayload.maxFeesEthText : ""
|
||||
enoughFunds: settings.enoughFunds
|
||||
estimatedTimeText: d.currentPayload ? d.currentPayload.estimatedTimeText : ""
|
||||
|
||||
account: d.selectedAccount
|
||||
network: d.selectedNetwork
|
||||
|
||||
onSign: {
|
||||
console.log("Sign button clicked")
|
||||
}
|
||||
onReject: {
|
||||
console.log("Reject button clicked")
|
||||
}
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
id: openButton
|
||||
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Layout.margins: 20
|
||||
|
||||
text: "Open DAppRequestModal"
|
||||
|
||||
onClicked: root.openModal()
|
||||
}
|
||||
|
||||
ColumnLayout {}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: optionsSpace
|
||||
|
||||
TextField {
|
||||
id: dappNameTextField
|
||||
|
||||
text: settings.dappName
|
||||
onTextChanged: settings.dappName = text
|
||||
}
|
||||
TextField {
|
||||
id: dappUrlTextField
|
||||
|
||||
text: settings.dappUrl
|
||||
onTextChanged: settings.dappUrl = text
|
||||
}
|
||||
TextField {
|
||||
id: dappIconTextField
|
||||
|
||||
text: settings.dappIcon
|
||||
onTextChanged: settings.dappIcon = text
|
||||
}
|
||||
TextField {
|
||||
id: accountDisplayTextField
|
||||
|
||||
text: settings.accountDisplay
|
||||
onTextChanged: settings.accountDisplay = text
|
||||
}
|
||||
StatusComboBox {
|
||||
id: methodsComboBox
|
||||
|
||||
model: d.methodsModel
|
||||
control.textRole: "method"
|
||||
currentIndex: settings.payloadMethod
|
||||
onCurrentIndexChanged: {
|
||||
d.currentPayload = null
|
||||
settings.payloadMethod = currentIndex
|
||||
d.currentPayload = d.payloadOptions[currentIndex]
|
||||
}
|
||||
}
|
||||
StatusCheckBox {
|
||||
id: enoughFundsCheckBox
|
||||
|
||||
text: "Enough funds"
|
||||
checked: settings.enoughFunds
|
||||
onCheckedChanged: settings.enoughFunds = checked
|
||||
}
|
||||
|
||||
Item { Layout.fillHeight: true }
|
||||
}
|
||||
}
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
|
||||
property string dappName: "OpenSea"
|
||||
property string dappUrl: "opensea.io"
|
||||
property string dappIcon: "https://opensea.io/static/images/logos/opensea-logo.svg"
|
||||
property string accountDisplay: "helloworld"
|
||||
property int payloadMethod: 0
|
||||
property bool enoughFunds: true
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
Component.onCompleted: methodsModel.append(payloadOptions)
|
||||
|
||||
readonly property var accountsModel: WalletAccountsModel{}
|
||||
readonly property var selectedAccount: accountsModel.data[0]
|
||||
|
||||
readonly property var selectedNetwork: NetworksModel.flatNetworks.get(0)
|
||||
|
||||
readonly property ListModel methodsModel: ListModel {}
|
||||
property var currentPayload: payloadOptions[settings.payloadMethod]
|
||||
property string maxFeesText: ""
|
||||
property string estimatedTimeText: ""
|
||||
|
||||
readonly property var payloadOptions: [
|
||||
{
|
||||
payloadData: {"message":"This is a message to sign.\nSigning this will prove ownership of the account."},
|
||||
method: SessionRequest.methods.personalSign.name,
|
||||
maxFeesText: "",
|
||||
maxFeesEthText: "",
|
||||
estimatedTimeText: ""
|
||||
},
|
||||
{
|
||||
payloadData: {"message": "{\"types\":{\"EIP712Domain\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"version\",\"type\":\"string\"},{\"name\":\"chainId\",\"type\":\"uint256\"},{\"name\":\"verifyingContract\",\"type\":\"address\"}],\"Person\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"wallet\",\"type\":\"address\"}],\"Mail\":[{\"name\":\"from\",\"type\":\"Person\"},{\"name\":\"to\",\"type\":\"Person\"},{\"name\":\"contents\",\"type\":\"string\"}]},\"primaryType\":\"Mail\",\"domain\":{\"name\":\"Ether Mail\",\"version\":\"1\",\"chainId\":1,\"verifyingContract\":\"0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC\"},\"message\":{\"from\":{\"name\":\"Cow\",\"wallet\":\"0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826\"},\"to\":{\"name\":\"Bob\",\"wallet\":\"0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB\"},\"contents\":\"Hello, Bob!\"}}"},
|
||||
method: SessionRequest.methods.signTypedData_v4.name,
|
||||
maxFeesText: "",
|
||||
maxFeesEthText: "",
|
||||
estimatedTimeText: ""
|
||||
},
|
||||
{
|
||||
payloadData: {"tx":{"data":"0x","from":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","gasLimit":"0x5208","gasPrice":"0x048ddbc5","nonce":"0x2a","to":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","value":"0x00"}},
|
||||
method: SessionRequest.methods.signTransaction.name,
|
||||
maxFeesText: "1.82 EUR",
|
||||
maxFeesEthText: "0.0001 ETH",
|
||||
estimatedTimeText: "3-5 mins"
|
||||
},
|
||||
{
|
||||
payloadData: {"tx":{"data":"0x","from":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","gasLimit":"0x5208","gasPrice":"0x048ddbc5","nonce":"0x2a","to":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","value":"0x00"}},
|
||||
method: SessionRequest.methods.sendTransaction.name,
|
||||
maxFeesText: "0.92 EUR",
|
||||
maxFeesEthText: "0.00005 ETH",
|
||||
estimatedTimeText: "1-2 mins"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// category: Wallet
|
|
@ -0,0 +1,137 @@
|
|||
// category: Popups
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import shared.popups.walletconnect 1.0
|
||||
import utils 1.0
|
||||
import Storybook 1.0
|
||||
|
||||
SplitView {
|
||||
id: root
|
||||
|
||||
PopupBackground {
|
||||
SplitView.fillWidth: true
|
||||
SplitView.fillHeight: true
|
||||
Button {
|
||||
anchors.centerIn: parent
|
||||
text: "Open"
|
||||
onClicked: dappSignRequestModal.visible = true
|
||||
}
|
||||
|
||||
DAppSignRequestModal {
|
||||
id: dappSignRequestModal
|
||||
|
||||
loginType: loginType.currentValue
|
||||
visible: true
|
||||
modal: false
|
||||
closePolicy: Popup.NoAutoClose
|
||||
dappUrl: "https://example.com"
|
||||
dappIcon: "https://picsum.photos/200/200"
|
||||
dappName: "OpenSea"
|
||||
accountColor: "blue"
|
||||
accountName: "Account Name"
|
||||
accountAddress: "0xE2d622C817878dA5143bBE06866ca8E35273Ba8"
|
||||
networkName: "Ethereum"
|
||||
networkIconPath: "https://picsum.photos/200/200"
|
||||
|
||||
currentCurrency: "EUR"
|
||||
fiatFees: fiatFees.text
|
||||
cryptoFees: "0.001"
|
||||
estimatedTime: "3-5 minutes"
|
||||
feesLoading: feesLoading.checked
|
||||
hasFees: hasFees.checked
|
||||
enoughFundsForTransaction: enoughFeesForTransaction.checked
|
||||
enoughFundsForFees: enoughFeesForGas.checked
|
||||
|
||||
// sun emoji
|
||||
accountEmoji: "\u2600"
|
||||
requestPayload: controls.contentToSign[contentToSignComboBox.currentIndex]
|
||||
signingTransaction: signingTransaction.checked
|
||||
|
||||
onAccepted: print ("Accepted")
|
||||
onRejected: print ("Rejected")
|
||||
}
|
||||
}
|
||||
Pane {
|
||||
id: controls
|
||||
SplitView.preferredWidth: 300
|
||||
SplitView.fillHeight: true
|
||||
|
||||
readonly property var contentToSign: ['{
|
||||
"id": 1714038548266495,
|
||||
"params": {
|
||||
"chainld": "eip155:11155111",
|
||||
"request": {
|
||||
"expiryTimestamp": 1714038848,
|
||||
"method": "eth_signTransaction",
|
||||
"params": [{
|
||||
"data": "0x",
|
||||
"from": "0xE2d622C817878dA5143bBE06866ca8E35273Ba8",
|
||||
"gasLimit": "0x5208",
|
||||
"gasPrice": "0xa677ef31",
|
||||
"nonce": "0x27",
|
||||
"to": "0xE2d622C817878dA5143bBE06866ca8E35273Ba8a",
|
||||
"value": "0x00"
|
||||
}]
|
||||
}
|
||||
},
|
||||
"topic": "a0f85b23a1f3a540d85760a523963165fb92169d57320c",
|
||||
"verifyContext": {
|
||||
"verified": {
|
||||
"isScam": false,
|
||||
"origin": "https://react-app.walletconnect.com/",
|
||||
"validation": "VALID",
|
||||
"verifyUrl": "https://verify.walletconnect.com/"
|
||||
}
|
||||
}
|
||||
}',
|
||||
'"tx":{"data":"0x","from":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","gasLimit":"0x5208","gasPrice":"0x048ddbc5","nonce":"0x2a","to":"0xE2d622C817878dA5143bBE06866ca8E35273Ba8a","value":"0x00"}',
|
||||
""
|
||||
]
|
||||
|
||||
ColumnLayout {
|
||||
TextField {
|
||||
id: fiatFees
|
||||
text: "1.54"
|
||||
}
|
||||
ComboBox {
|
||||
id: loginType
|
||||
model: [{name: "Password", value: Constants.LoginType.Password}, {name: "Biometrics", value: Constants.LoginType.Biometrics}, {name: "Keycard", value: Constants.LoginType.Keycard}]
|
||||
textRole: "name"
|
||||
valueRole: "value"
|
||||
currentIndex: 0
|
||||
}
|
||||
ComboBox {
|
||||
id: contentToSignComboBox
|
||||
model: ["Long content to sign", "Short content to sign", "Empty content to sign"]
|
||||
currentIndex: 0
|
||||
}
|
||||
CheckBox {
|
||||
id: enoughFeesForTransaction
|
||||
text: "Enough fees for transaction"
|
||||
checked: true
|
||||
}
|
||||
CheckBox {
|
||||
id: enoughFeesForGas
|
||||
text: "Enough fees for gas"
|
||||
checked: true
|
||||
}
|
||||
CheckBox {
|
||||
id: feesLoading
|
||||
text: "Fees loading"
|
||||
checked: false
|
||||
}
|
||||
CheckBox {
|
||||
id: hasFees
|
||||
text: "Has fees"
|
||||
checked: true
|
||||
}
|
||||
CheckBox {
|
||||
id: signingTransaction
|
||||
text: "Signing transaction"
|
||||
checked: false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -61,6 +61,8 @@ Item {
|
|||
spacing: 8
|
||||
|
||||
wcService: walletConnectService
|
||||
loginType: Constants.LoginType.Biometrics
|
||||
selectedAccountAddress: ""
|
||||
}
|
||||
}
|
||||
ColumnLayout {}
|
||||
|
@ -373,7 +375,6 @@ Item {
|
|||
}
|
||||
|
||||
walletRootStore: QObject {
|
||||
property string selectedAddress: ""
|
||||
property var filteredFlatModel: SortFilterProxyModel {
|
||||
sourceModel: NetworksModel.flatNetworks
|
||||
filters: ValueFilter { roleName: "isTest"; value: settings.testNetworks; }
|
||||
|
|
|
@ -121,7 +121,6 @@ Item {
|
|||
id: walletStoreComponent
|
||||
|
||||
QtObject {
|
||||
property string selectedAddress: ""
|
||||
readonly property ListModel filteredFlatModel: ListModel {
|
||||
ListElement { chainId: 1 }
|
||||
ListElement {
|
||||
|
@ -503,6 +502,7 @@ Item {
|
|||
Component {
|
||||
id: componentUnderTest
|
||||
DAppsWorkflow {
|
||||
loginType: Constants.LoginType.Password
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -605,9 +605,9 @@ Item {
|
|||
verify(popup.visible)
|
||||
|
||||
compare(popup.dappName, td.session.peer.metadata.name)
|
||||
compare(popup.account.name, td.account.name)
|
||||
compare(popup.account.address, td.account.address)
|
||||
compare(popup.network.chainId, td.network.chainId)
|
||||
compare(popup.accountName, td.account.name)
|
||||
compare(popup.accountAddress, td.account.address)
|
||||
compare(popup.networkName, td.network.chainName)
|
||||
|
||||
popup.close()
|
||||
waitForRendering(controlUnderTest)
|
||||
|
|
|
@ -93,16 +93,16 @@ Item {
|
|||
.arg(controlUnderTest.formatBigNumber(controlUnderTest.fromTokenAmount)).arg(controlUnderTest.fromTokenSymbol)
|
||||
.arg(controlUnderTest.accountName).arg(controlUnderTest.serviceProviderURL).arg(controlUnderTest.networkName))
|
||||
|
||||
const fromImageHidden = findChild(controlUnderTest.contentItem, "fromImage")
|
||||
const fromImageHidden = findChild(controlUnderTest.contentItem, "fromImageIdenticon")
|
||||
compare(fromImageHidden.visible, false)
|
||||
|
||||
const fromImage = findChild(controlUnderTest.contentItem, "fromImageIdenticon")
|
||||
verify(!!fromImage)
|
||||
compare(fromImage.asset.emoji, controlUnderTest.accountEmoji)
|
||||
compare(fromImage.asset.color, controlUnderTest.accountColor)
|
||||
const toImage = findChild(controlUnderTest.contentItem, "toImage")
|
||||
const toImage = findChild(controlUnderTest.contentItem, "toImageIdenticon")
|
||||
verify(!!toImage)
|
||||
compare(toImage.image.source, Constants.tokenIcon(controlUnderTest.fromTokenSymbol))
|
||||
compare(toImage.asset.name, Constants.tokenIcon(controlUnderTest.fromTokenSymbol))
|
||||
|
||||
// spending cap box
|
||||
const spendingCapBox = findChild(controlUnderTest.contentItem, "spendingCapBox")
|
||||
|
|
|
@ -95,12 +95,12 @@ Item {
|
|||
const headerText = findChild(controlUnderTest.contentItem, "headerText")
|
||||
verify(!!headerText)
|
||||
compare(headerText.text, qsTr("Swap 1000.123456789 SNT to 1.42 ETH in %1 on %2").arg(controlUnderTest.accountName).arg(controlUnderTest.networkName))
|
||||
const fromImage = findChild(controlUnderTest.contentItem, "fromImage")
|
||||
const fromImage = findChild(controlUnderTest.contentItem, "fromImageIdenticon")
|
||||
verify(!!fromImage)
|
||||
compare(fromImage.image.source, Constants.tokenIcon(controlUnderTest.fromTokenSymbol))
|
||||
const toImage = findChild(controlUnderTest.contentItem, "toImage")
|
||||
compare(fromImage.asset.name, Constants.tokenIcon(controlUnderTest.fromTokenSymbol))
|
||||
const toImage = findChild(controlUnderTest.contentItem, "toImageIdenticon")
|
||||
verify(!!toImage)
|
||||
compare(toImage.image.source, Constants.tokenIcon(controlUnderTest.toTokenSymbol))
|
||||
compare(toImage.asset.name, Constants.tokenIcon(controlUnderTest.toTokenSymbol))
|
||||
|
||||
// pay box
|
||||
const payBox = findChild(controlUnderTest.contentItem, "payBox")
|
||||
|
|
|
@ -165,6 +165,7 @@
|
|||
<file>assets/img/icons/checkmark.svg</file>
|
||||
<file>assets/img/icons/chevron-down.svg</file>
|
||||
<file>assets/img/icons/chevron-up.svg</file>
|
||||
<file>assets/img/icons/collapse.svg</file>
|
||||
<file>assets/img/icons/clear.svg</file>
|
||||
<file>assets/img/icons/close-circle.svg</file>
|
||||
<file>assets/img/icons/close.svg</file>
|
||||
|
@ -187,6 +188,7 @@
|
|||
<file>assets/img/icons/emojis.svg</file>
|
||||
<file>assets/img/icons/ETH.png</file>
|
||||
<file>assets/img/icons/exchange.svg</file>
|
||||
<file>assets/img/icons/expand.svg</file>
|
||||
<file>assets/img/icons/external.svg</file>
|
||||
<file>assets/img/icons/external-link.svg</file>
|
||||
<file>assets/img/icons/face-id.svg</file>
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Arrow / Collapse">
|
||||
<g id="Icon">
|
||||
<path d="M12.7959 4.65686C12.7959 4.24264 13.1317 3.90686 13.5459 3.90686C13.9602 3.90686 14.2959 4.24264 14.2959 4.65686L14.2959 7.29594C14.2959 7.74139 14.8345 7.96448 15.1495 7.6495L19.3293 3.46967C19.6222 3.17678 20.0971 3.17678 20.39 3.46967C20.6829 3.76256 20.6829 4.23744 20.39 4.53033L16.2102 8.71016C15.8952 9.02514 16.1183 9.56371 16.5637 9.56371L19.2028 9.56371C19.617 9.56371 19.9528 9.89949 19.9528 10.3137C19.9528 10.7279 19.617 11.0637 19.2028 11.0637L13.5459 11.0637C13.1317 11.0637 12.7959 10.7279 12.7959 10.3137L12.7959 4.65686Z" fill="#939BA1"/>
|
||||
<path d="M4.54594 12.7647C4.13173 12.7647 3.79594 13.1005 3.79594 13.5147C3.79594 13.9289 4.13173 14.2647 4.54594 14.2647L7.18503 14.2647C7.63048 14.2647 7.85356 14.8033 7.53858 15.1183L3.35875 19.2981C3.06586 19.591 3.06586 20.0659 3.35876 20.3588C3.65165 20.6517 4.12652 20.6517 4.41942 20.3588L8.59924 16.1789C8.91422 15.864 9.45279 16.087 9.45279 16.5325L9.45279 19.1716C9.45279 19.5858 9.78858 19.9216 10.2028 19.9216C10.617 19.9216 10.9528 19.5858 10.9528 19.1716V13.5147C10.9528 13.1005 10.617 12.7647 10.2028 12.7647L4.54594 12.7647Z" fill="#939BA1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
|
@ -0,0 +1,8 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="Arrow / Expand">
|
||||
<g id="Icon">
|
||||
<path d="M3.21016 14.2426C3.21016 13.8284 3.54594 13.4926 3.96016 13.4926C4.37437 13.4926 4.71016 13.8284 4.71016 14.2426L4.71015 16.8817C4.71015 17.3272 5.24873 17.5503 5.56371 17.2353L9.74353 13.0555C10.0364 12.7626 10.5113 12.7626 10.8042 13.0555C11.0971 13.3484 11.0971 13.8232 10.8042 14.1161L6.62437 18.2959C6.30939 18.6109 6.53247 19.1495 6.97792 19.1495L9.61701 19.1495C10.0312 19.1495 10.367 19.4853 10.367 19.8995C10.367 20.3137 10.0312 20.6495 9.61701 20.6495L3.96016 20.6495C3.54594 20.6495 3.21016 20.3137 3.21016 19.8995L3.21016 14.2426Z" fill="#939BA1"/>
|
||||
<path d="M13.9602 3.35051C13.5459 3.35051 13.2102 3.68629 13.2102 4.10051C13.2102 4.51472 13.5459 4.85051 13.9602 4.85051L16.5992 4.85051C17.0447 4.85051 17.2678 5.38908 16.9528 5.70406L12.773 9.88388C12.4801 10.1768 12.4801 10.6517 12.773 10.9445C13.0659 11.2374 13.5407 11.2374 13.8336 10.9445L18.0135 6.76472C18.3284 6.44974 18.867 6.67282 18.867 7.11828L18.867 9.75736C18.867 10.1716 19.2028 10.5074 19.617 10.5074C20.0312 10.5074 20.367 10.1716 20.367 9.75736L20.367 4.10051C20.367 3.68629 20.0312 3.35051 19.617 3.35051L13.9602 3.35051Z" fill="#939BA1"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
|
@ -11,13 +11,15 @@ import shared.popups.walletconnect 1.0
|
|||
import AppLayouts.Wallet.services.dapps 1.0
|
||||
import AppLayouts.Wallet.services.dapps.types 1.0
|
||||
|
||||
import shared.stores 1.0
|
||||
import utils 1.0
|
||||
|
||||
DappsComboBox {
|
||||
id: root
|
||||
|
||||
required property WalletConnectService wcService
|
||||
// Values mapped to Constants.LoginType
|
||||
required property int loginType
|
||||
property string selectedAccountAddress
|
||||
|
||||
signal pairWCReady()
|
||||
|
||||
|
@ -85,7 +87,7 @@ DappsComboBox {
|
|||
}
|
||||
]
|
||||
}
|
||||
selectedAccountAddress: root.wcService.selectedAccountAddress
|
||||
selectedAccountAddress: root.selectedAccountAddress
|
||||
|
||||
dAppUrl: proposalMedatada.url
|
||||
dAppName: proposalMedatada.name
|
||||
|
@ -116,26 +118,62 @@ DappsComboBox {
|
|||
|
||||
property SessionRequestResolved request: null
|
||||
|
||||
sourceComponent: DAppRequestModal {
|
||||
account: request.account
|
||||
network: request.network
|
||||
|
||||
dappName: request.dappName
|
||||
dappUrl: request.dappUrl
|
||||
dappIcon: request.dappIcon
|
||||
|
||||
payloadData: request.data
|
||||
method: request.method
|
||||
maxFeesText: request.maxFeesText
|
||||
maxFeesEthText: request.maxFeesEthText
|
||||
enoughFunds: request.enoughFunds
|
||||
estimatedTimeText: request.estimatedTimeText
|
||||
|
||||
sourceComponent: DAppSignRequestModal {
|
||||
objectName: "dappsRequestModal"
|
||||
loginType: request.account.migragedToKeycard ? Constants.LoginType.Keycard : root.loginType
|
||||
visible: true
|
||||
|
||||
onClosed: sessionRequestLoader.active = false
|
||||
dappUrl: request.dappUrl
|
||||
dappIcon: request.dappIcon
|
||||
dappName: request.dappName
|
||||
|
||||
onSign: {
|
||||
accountColor: request.account.color
|
||||
accountName: request.account.name
|
||||
accountAddress: request.account.address
|
||||
accountEmoji: request.account.emoji
|
||||
|
||||
networkName: request.network.chainName
|
||||
networkIconPath: Style.svg(request.network.iconUrl)
|
||||
|
||||
currentCurrency: ""
|
||||
fiatFees: request.maxFeesText
|
||||
cryptoFees: request.maxFeesEthText
|
||||
estimatedTime: request.estimatedTimeText
|
||||
feesLoading: !request.maxFeesText || !request.maxFeesEthText
|
||||
hasFees: signingTransaction
|
||||
enoughFundsForTransaction: request.enoughFunds
|
||||
enoughFundsForFees: request.enoughFunds
|
||||
|
||||
signingTransaction: request.method === SessionRequest.methods.signTransaction.name || request.method === SessionRequest.methods.sendTransaction.name
|
||||
requestPayload: {
|
||||
switch(request.method) {
|
||||
case SessionRequest.methods.personalSign.name:
|
||||
return SessionRequest.methods.personalSign.getMessageFromData(request.data)
|
||||
case SessionRequest.methods.sign.name: {
|
||||
return SessionRequest.methods.sign.getMessageFromData(request.data)
|
||||
}
|
||||
case SessionRequest.methods.signTypedData_v4.name: {
|
||||
const stringPayload = SessionRequest.methods.signTypedData_v4.getMessageFromData(request.data)
|
||||
return JSON.stringify(JSON.parse(stringPayload), null, 2)
|
||||
}
|
||||
case SessionRequest.methods.signTypedData.name: {
|
||||
const stringPayload = SessionRequest.methods.signTypedData.getMessageFromData(root.payloadData)
|
||||
return JSON.stringify(JSON.parse(stringPayload), null, 2)
|
||||
}
|
||||
case SessionRequest.methods.signTransaction.name: {
|
||||
const jsonPayload = SessionRequest.methods.signTransaction.getTxObjFromData(request.data)
|
||||
return JSON.stringify(jsonPayload, null, 2)
|
||||
}
|
||||
case SessionRequest.methods.sendTransaction.name: {
|
||||
const jsonPayload = SessionRequest.methods.sendTransaction.getTxObjFromData(request.data)
|
||||
return JSON.stringify(jsonPayload, null, 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onClosed: Qt.callLater( () => sessionRequestLoader.active = false)
|
||||
|
||||
onAccepted: {
|
||||
if (!request) {
|
||||
console.error("Error signing: request is null")
|
||||
return
|
||||
|
@ -143,28 +181,32 @@ DappsComboBox {
|
|||
root.wcService.requestHandler.authenticate(request)
|
||||
}
|
||||
|
||||
onReject: {
|
||||
onRejected: {
|
||||
let userRejected = true
|
||||
root.wcService.requestHandler.rejectSessionRequest(request, userRejected)
|
||||
close()
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root.wcService.requestHandler
|
||||
|
||||
function onMaxFeesUpdated(maxFees, maxFeesWei, haveEnoughFunds, symbol) {
|
||||
maxFeesText = `${maxFees.toFixed(2)} ${symbol}`
|
||||
fiatFees = maxFees
|
||||
currentCurrency = symbol
|
||||
|
||||
var ethStr = "?"
|
||||
try {
|
||||
ethStr = globalUtils.wei2Eth(maxFeesWei, 9)
|
||||
} catch (e) {
|
||||
// ignore error in case of tests and storybook where we don't have access to globalUtils
|
||||
}
|
||||
maxFeesEthText = `${ethStr} ETH`
|
||||
enoughFunds = haveEnoughFunds
|
||||
cryptoFees = ethStr
|
||||
enoughFundsForTransaction = haveEnoughFunds
|
||||
enoughFundsForFees = haveEnoughFunds
|
||||
feesLoading = false
|
||||
hasFees = !!maxFees
|
||||
}
|
||||
function onEstimatedTimeUpdated(minMinutes, maxMinutes) {
|
||||
estimatedTimeText = qsTr("%1-%2mins").arg(minMinutes).arg(maxMinutes)
|
||||
estimatedTime = qsTr("%1-%2mins").arg(minMinutes).arg(maxMinutes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,8 @@ Item {
|
|||
enabled: !!Global.walletConnectService
|
||||
|
||||
wcService: Global.walletConnectService
|
||||
loginType: root.store.loginType
|
||||
selectedAccountAddress: root.walletStore.selectedAddress
|
||||
}
|
||||
|
||||
StatusButton {
|
||||
|
|
|
@ -2,6 +2,7 @@ import QtQuick 2.15
|
|||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml.Models 2.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Core 0.1
|
||||
|
@ -24,6 +25,7 @@ StatusDialog {
|
|||
property Component headerIconComponent
|
||||
|
||||
property bool feesLoading
|
||||
property bool signButtonEnabled: true
|
||||
|
||||
property ObjectModel leftFooterContents
|
||||
property ObjectModel rightFooterContents: ObjectModel {
|
||||
|
@ -39,7 +41,7 @@ StatusDialog {
|
|||
StatusButton {
|
||||
objectName: "signButton"
|
||||
id: signButton
|
||||
interactive: !root.feesLoading
|
||||
interactive: !root.feesLoading && root.signButtonEnabled
|
||||
icon.name: Constants.authenticationIconByType[root.loginType]
|
||||
text: qsTr("Sign")
|
||||
onClicked: root.accept() // close and emit accepted() signal
|
||||
|
@ -51,11 +53,14 @@ StatusDialog {
|
|||
property url fromImageSource
|
||||
property alias fromImageSmartIdenticon: fromImageSmartIdenticon
|
||||
property url toImageSource
|
||||
readonly property alias toImageSmartIdenticon: toImageSmartIdenticon
|
||||
property alias headerMainText: headerMainText.text
|
||||
property alias headerSubTextLayout: headerSubTextLayout.children
|
||||
readonly property alias headerSubTextLayout: headerSubTextLayout.children
|
||||
property string infoTagText
|
||||
readonly property alias infoTag: infoTag
|
||||
property bool showHeaderDivider: true
|
||||
|
||||
default property alias contents: contentsLayout.children
|
||||
default property alias contents: contentsLayout.data
|
||||
|
||||
width: 480
|
||||
padding: 0
|
||||
|
@ -127,26 +132,48 @@ StatusDialog {
|
|||
id: fromImageSmartIdenticon
|
||||
width: 40
|
||||
height: 40
|
||||
asset.name: root.fromImageSource
|
||||
asset.width: 40
|
||||
asset.height: 40
|
||||
asset.bgWidth: 40
|
||||
asset.bgHeight: 40
|
||||
asset.color: "transparent"
|
||||
asset.bgColor: "transparent"
|
||||
visible: !!asset.name
|
||||
layer.enabled: toImageSmartIdenticon.visible
|
||||
layer.effect: OpacityMask {
|
||||
id: mask
|
||||
invert: true
|
||||
|
||||
maskSource: Item {
|
||||
width: mask.width + 4
|
||||
height: mask.height + 4
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
anchors.horizontalCenterOffset: toImageSmartIdenticon.width - 10
|
||||
|
||||
width: parent.width
|
||||
height: width
|
||||
radius: width / 2
|
||||
}
|
||||
StatusRoundedImage {
|
||||
objectName: "fromImage"
|
||||
width: 42
|
||||
height: 42
|
||||
border.width: 2
|
||||
border.color: "transparent"
|
||||
image.source: root.fromImageSource
|
||||
visible: root.fromImageSource.toString() !== ""
|
||||
}
|
||||
StatusRoundedImage {
|
||||
objectName: "toImage"
|
||||
width: 42
|
||||
height: 42
|
||||
border.width: 2
|
||||
border.color: Theme.palette.statusBadge.foregroundColor
|
||||
image.source: root.toImageSource
|
||||
}
|
||||
}
|
||||
|
||||
StatusSmartIdenticon {
|
||||
objectName: "toImageIdenticon"
|
||||
id: toImageSmartIdenticon
|
||||
width: 40
|
||||
height: 40
|
||||
asset.bgWidth: 40
|
||||
asset.bgHeight: 40
|
||||
visible: !!asset.name || !!asset.source
|
||||
asset.name: root.toImageSource
|
||||
asset.width: 40
|
||||
asset.height: 40
|
||||
asset.color: "transparent"
|
||||
asset.bgColor: "transparent"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,6 +209,7 @@ StatusDialog {
|
|||
StatusDialogDivider {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
visible: root.showHeaderDivider
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
|
|
@ -159,6 +159,13 @@ QObject {
|
|||
obj.resolveDappInfoFromSession(session)
|
||||
root.sessionRequest(obj)
|
||||
// TODO #15192: update maxFees
|
||||
if (!event.params.request.params[0].gasLimit || !event.params.request.params[0].gasPrice) {
|
||||
root.maxFeesUpdated(0, 0, true, "")
|
||||
root.estimatedTimeUpdated(0, 0)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let gasLimit = parseFloat(parseInt(event.params.request.params[0].gasLimit, 16));
|
||||
let gasPrice = parseFloat(parseInt(event.params.request.params[0].gasPrice, 16));
|
||||
let maxFees = gasLimit * gasPrice
|
||||
|
|
|
@ -32,8 +32,6 @@ QObject {
|
|||
required property DAppsStore store
|
||||
required property var walletRootStore
|
||||
|
||||
readonly property string selectedAccountAddress: walletRootStore.selectedAddress
|
||||
|
||||
readonly property alias dappsModel: dappsProvider.dappsModel
|
||||
readonly property alias requestHandler: requestHandler
|
||||
|
||||
|
|
|
@ -1,362 +0,0 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml.Models 2.15
|
||||
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Popups.Dialog 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Components 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1 as StatusQ
|
||||
|
||||
import shared.popups.walletconnect.panels 1.0
|
||||
import utils 1.0
|
||||
|
||||
import AppLayouts.Wallet.services.dapps.types 1.0
|
||||
|
||||
StatusDialog {
|
||||
id: root
|
||||
|
||||
objectName: "dappsRequestModal"
|
||||
|
||||
implicitWidth: 480
|
||||
|
||||
required property string dappName
|
||||
required property string dappUrl
|
||||
required property url dappIcon
|
||||
required property string method
|
||||
required property var payloadData
|
||||
property string maxFeesText: ""
|
||||
property string maxFeesEthText: ""
|
||||
property bool enoughFunds: false
|
||||
property string estimatedTimeText: ""
|
||||
|
||||
required property var account
|
||||
property var network: null
|
||||
|
||||
signal sign()
|
||||
signal reject()
|
||||
|
||||
title: qsTr("Sign request")
|
||||
|
||||
padding: 20
|
||||
|
||||
onPayloadDataChanged: d.updateDisplay()
|
||||
onMethodChanged: d.updateDisplay()
|
||||
Component.onCompleted: d.updateDisplay()
|
||||
|
||||
contentItem: StatusScrollView {
|
||||
id: scrollView
|
||||
padding: 0
|
||||
ColumnLayout {
|
||||
spacing: 20
|
||||
clip: true
|
||||
|
||||
width: scrollView.availableWidth
|
||||
|
||||
IntentionPanel {
|
||||
Layout.fillWidth: true
|
||||
|
||||
dappName: root.dappName
|
||||
dappIcon: root.dappIcon
|
||||
account: root.account
|
||||
|
||||
userDisplayNaming: d.userDisplayNaming
|
||||
}
|
||||
|
||||
ContentPanel {
|
||||
Layout.fillWidth: true
|
||||
Layout.maximumHeight: 340
|
||||
|
||||
payloadToDisplay: d.payloadToDisplay
|
||||
}
|
||||
|
||||
// TODO: externalize as a TargetPanel
|
||||
ColumnLayout {
|
||||
spacing: 8
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Sign with")
|
||||
font.pixelSize: 13
|
||||
color: Theme.palette.directColor1
|
||||
}
|
||||
|
||||
// TODO #14762: implement proper control to display the accounts details
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 76
|
||||
|
||||
radius: 8
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
color: "transparent"
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
|
||||
StatusSmartIdenticon {
|
||||
width: 40
|
||||
height: 40
|
||||
|
||||
asset: StatusAssetSettings {
|
||||
color: Theme.palette.primaryColor1
|
||||
isImage: false
|
||||
isLetterIdenticon: true
|
||||
useAcronymForLetterIdenticon: false
|
||||
emoji: root.account.emoji
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
StatusBaseText {
|
||||
text: root.account.name
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
font.pixelSize: 13
|
||||
}
|
||||
StatusBaseText {
|
||||
text: StatusQ.Utils.elideAndFormatWalletAddress(root.account.address, 6, 4)
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
font.pixelSize: 13
|
||||
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
}
|
||||
|
||||
Item {Layout.fillWidth: true }
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Network")
|
||||
font.pixelSize: 13
|
||||
color: Theme.palette.directColor1
|
||||
}
|
||||
|
||||
// TODO #14762: implement proper control to display the chain
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 76
|
||||
|
||||
visible: root.network !== null
|
||||
|
||||
radius: 8
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
color: "transparent"
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
|
||||
StatusSmartIdenticon {
|
||||
width: 40
|
||||
height: 40
|
||||
|
||||
asset: StatusAssetSettings {
|
||||
isImage: true
|
||||
name: !!root.network ? Style.svg("tiny/" + root.network.iconUrl) : ""
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: !!root.network ? root.network.chainName : ""
|
||||
|
||||
Layout.alignment: Qt.AlignLeft
|
||||
|
||||
font.pixelSize: 13
|
||||
}
|
||||
Item {Layout.fillWidth: true }
|
||||
}
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Fees")
|
||||
font.pixelSize: 13
|
||||
color: Theme.palette.directColor1
|
||||
visible: d.isTransaction()
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 76
|
||||
|
||||
visible: root.network !== null && d.isTransaction()
|
||||
|
||||
radius: 8
|
||||
border.width: 1
|
||||
border.color: Theme.palette.baseColor2
|
||||
color: "transparent"
|
||||
|
||||
RowLayout {
|
||||
spacing: 12
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
|
||||
StatusBaseText {
|
||||
text: qsTr("Max. fees on %1").arg(!!root.network && root.network.chainName)
|
||||
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
|
||||
font.pixelSize: 13
|
||||
color: Theme.palette.baseColor1
|
||||
}
|
||||
|
||||
Item {Layout.fillWidth: true }
|
||||
|
||||
ColumnLayout {
|
||||
StatusBaseText {
|
||||
text: root.maxFeesText
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
font.pixelSize: 13
|
||||
color: root.enoughFunds ? Theme.palette.directColor1 : Theme.palette.dangerColor1
|
||||
}
|
||||
|
||||
StatusBaseText {
|
||||
text: root.maxFeesEthText
|
||||
|
||||
Layout.alignment: Qt.AlignRight
|
||||
|
||||
font.pixelSize: 13
|
||||
color: root.enoughFunds ? Theme.palette.baseColor1 : Theme.palette.dangerColor1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header: StatusDialogHeader {
|
||||
leftComponent: Item {
|
||||
width: 46
|
||||
height: 46
|
||||
|
||||
StatusSmartIdenticon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 3
|
||||
|
||||
asset: StatusAssetSettings {
|
||||
width: 40
|
||||
height: 40
|
||||
bgRadius: bgWidth / 2
|
||||
imgIsIdenticon: false
|
||||
isImage: true
|
||||
useAcronymForLetterIdenticon: false
|
||||
name: root.dappIcon
|
||||
}
|
||||
bridgeBadge.visible: true
|
||||
bridgeBadge.width: 16
|
||||
bridgeBadge.height: 16
|
||||
bridgeBadge.image.source: "assets/sign.svg"
|
||||
bridgeBadge.border.width: 3
|
||||
bridgeBadge.border.color: "transparent"
|
||||
bridgeBadge.color: Theme.palette.miscColor1
|
||||
}
|
||||
}
|
||||
headline.title: qsTr("Sign request")
|
||||
headline.subtitle: root.dappUrl
|
||||
}
|
||||
|
||||
footer: StatusDialogFooter {
|
||||
id: footer
|
||||
|
||||
leftButtons: ObjectModel {
|
||||
MaxFeesDisplay {
|
||||
maxFeesText: root.maxFeesText
|
||||
feesTextColor: root.enoughFunds ? Theme.palette.directColor1 : Theme.palette.dangerColor1
|
||||
}
|
||||
Item {
|
||||
width: 20
|
||||
}
|
||||
EstimatedTimeDisplay {
|
||||
estimatedTimeText: root.estimatedTimeText
|
||||
visible: !!root.estimatedTimeText
|
||||
}
|
||||
}
|
||||
|
||||
rightButtons: ObjectModel {
|
||||
StatusButton {
|
||||
objectName: "rejectButton"
|
||||
|
||||
height: 44
|
||||
text: qsTr("Reject")
|
||||
|
||||
onClicked: {
|
||||
root.reject()
|
||||
}
|
||||
}
|
||||
StatusButton {
|
||||
height: 44
|
||||
text: qsTr("Sign")
|
||||
|
||||
onClicked: {
|
||||
root.sign()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
|
||||
property string payloadToDisplay: ""
|
||||
property string userDisplayNaming: ""
|
||||
|
||||
function isTransaction() {
|
||||
return root.method === SessionRequest.methods.signTransaction.name || root.method === SessionRequest.methods.sendTransaction.name
|
||||
}
|
||||
|
||||
function updateDisplay() {
|
||||
if (!root.payloadData)
|
||||
return
|
||||
|
||||
switch (root.method) {
|
||||
case SessionRequest.methods.personalSign.name: {
|
||||
payloadToDisplay = SessionRequest.methods.personalSign.getMessageFromData(root.payloadData)
|
||||
userDisplayNaming = SessionRequest.methods.personalSign.requestDisplay
|
||||
break
|
||||
}
|
||||
case SessionRequest.methods.sign.name: {
|
||||
payloadToDisplay = SessionRequest.methods.sign.getMessageFromData(root.payloadData)
|
||||
userDisplayNaming = SessionRequest.methods.sign.requestDisplay
|
||||
break
|
||||
}
|
||||
case SessionRequest.methods.signTypedData_v4.name: {
|
||||
let messageObject = SessionRequest.methods.signTypedData_v4.getMessageFromData(root.payloadData)
|
||||
payloadToDisplay = JSON.stringify(JSON.parse(messageObject), null, 2)
|
||||
userDisplayNaming = SessionRequest.methods.signTypedData_v4.requestDisplay
|
||||
break
|
||||
}
|
||||
case SessionRequest.methods.signTypedData.name: {
|
||||
let messageObject = SessionRequest.methods.signTypedData.getMessageFromData(root.payloadData)
|
||||
payloadToDisplay = JSON.stringify(JSON.parse(messageObject), null, 2)
|
||||
userDisplayNaming = SessionRequest.methods.signTypedData.requestDisplay
|
||||
break
|
||||
}
|
||||
case SessionRequest.methods.signTransaction.name: {
|
||||
let tx = SessionRequest.methods.signTransaction.getTxObjFromData(root.payloadData)
|
||||
payloadToDisplay = JSON.stringify(tx, null, 2)
|
||||
userDisplayNaming = SessionRequest.methods.signTransaction.requestDisplay
|
||||
break
|
||||
}
|
||||
case SessionRequest.methods.sendTransaction.name: {
|
||||
let tx = SessionRequest.methods.sendTransaction.getTxObjFromData(root.payloadData)
|
||||
payloadToDisplay = JSON.stringify(tx, null, 2)
|
||||
userDisplayNaming = SessionRequest.methods.sendTransaction.requestDisplay
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,192 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtQml.Models 2.15
|
||||
|
||||
import StatusQ 0.1
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
import StatusQ.Core.Utils 0.1 as SQUtils
|
||||
import AppLayouts.Wallet.popups 1.0
|
||||
import AppLayouts.Wallet.panels 1.0
|
||||
|
||||
import shared.popups.walletconnect.panels 1.0
|
||||
|
||||
import utils 1.0
|
||||
|
||||
SignTransactionModalBase {
|
||||
id: root
|
||||
|
||||
required property bool signingTransaction
|
||||
// DApp info
|
||||
required property url dappUrl
|
||||
required property url dappIcon
|
||||
required property string dappName
|
||||
// Payload to sign
|
||||
required property string requestPayload
|
||||
// Account
|
||||
required property color accountColor
|
||||
required property string accountName
|
||||
required property string accountEmoji
|
||||
required property string accountAddress
|
||||
// Network
|
||||
required property string networkName
|
||||
required property string networkIconPath
|
||||
// Fees
|
||||
required property string currentCurrency
|
||||
required property string fiatFees
|
||||
required property string cryptoFees
|
||||
required property string estimatedTime
|
||||
required property bool hasFees
|
||||
|
||||
property bool enoughFundsForTransaction: true
|
||||
property bool enoughFundsForFees: false
|
||||
|
||||
signButtonEnabled: enoughFundsForTransaction && enoughFundsForFees
|
||||
title: qsTr("Sign Request")
|
||||
subtitle: SQUtils.StringUtils.extractDomainFromLink(root.dappUrl)
|
||||
headerIconComponent: RoundImageWithBadge {
|
||||
imageUrl: root.dappIcon
|
||||
width: 40
|
||||
height: 40
|
||||
}
|
||||
|
||||
gradientColor: Utils.setColorAlpha(root.accountColor, 0.05) // 5% of wallet color
|
||||
headerMainText: root.signingTransaction ? qsTr("%1 wants you to sign this transaction with %2").arg(root.dappName).arg(root.accountName) :
|
||||
qsTr("%1 wants you to sign this message with %2").arg(root.dappName).arg(root.accountName)
|
||||
|
||||
fromImageSmartIdenticon.asset.name: "filled-account"
|
||||
fromImageSmartIdenticon.asset.emoji: root.accountEmoji
|
||||
fromImageSmartIdenticon.asset.color: root.accountColor
|
||||
fromImageSmartIdenticon.asset.isLetterIdenticon: !!root.accountEmoji
|
||||
toImageSmartIdenticon.asset.name: Style.svg("sign")
|
||||
toImageSmartIdenticon.asset.bgColor: Theme.palette.primaryColor3
|
||||
toImageSmartIdenticon.asset.width: 24
|
||||
toImageSmartIdenticon.asset.height: 24
|
||||
toImageSmartIdenticon.asset.color: Theme.palette.primaryColor1
|
||||
|
||||
infoTagText: qsTr("Only sign if you trust the dApp")
|
||||
infoTag.states: [
|
||||
State {
|
||||
name: "insufficientFunds"
|
||||
when: !root.enoughFundsForTransaction
|
||||
PropertyChanges {
|
||||
target: infoTag
|
||||
asset.color: Theme.palette.dangerColor1
|
||||
tagPrimaryLabel.color: Theme.palette.dangerColor1
|
||||
backgroundColor: Theme.palette.dangerColor3
|
||||
bgBorderColor: Theme.palette.dangerColor2
|
||||
tagPrimaryLabel.text: qsTr("Insufficient funds for transaction")
|
||||
}
|
||||
}
|
||||
]
|
||||
showHeaderDivider: !root.requestPayload
|
||||
|
||||
leftFooterContents: ObjectModel {
|
||||
RowLayout {
|
||||
Layout.leftMargin: 4
|
||||
spacing: Style.current.bigPadding
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
StatusBaseText {
|
||||
text: qsTr("Max fees:")
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
Layout.fillWidth: true
|
||||
objectName: "footerFiatFeesText"
|
||||
text: "%1 %2".arg(formatBigNumber(root.fiatFees)).arg(root.currentCurrency)
|
||||
loading: root.feesLoading
|
||||
customColor: root.enoughFundsForFees ? Theme.palette.directColor1 : Theme.palette.dangerColor1
|
||||
elide: Qt.ElideMiddle
|
||||
Binding on text {
|
||||
when: !root.hasFees
|
||||
value: qsTr("No fees")
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
visible: root.hasFees
|
||||
StatusBaseText {
|
||||
text: qsTr("Est. time:")
|
||||
color: Theme.palette.baseColor1
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "footerEstimatedTime"
|
||||
text: root.estimatedTime
|
||||
loading: root.feesLoading
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Payload
|
||||
ContentPanel {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
payloadToDisplay: root.requestPayload
|
||||
visible: !!root.requestPayload
|
||||
}
|
||||
|
||||
// Account
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "accountBox"
|
||||
caption: qsTr("Sign with")
|
||||
primaryText: root.accountName
|
||||
secondaryText: SQUtils.Utils.elideAndFormatWalletAddress(root.accountAddress)
|
||||
asset.name: "filled-account"
|
||||
asset.emoji: root.accountEmoji
|
||||
asset.color: root.accountColor
|
||||
asset.isLetterIdenticon: !!root.accountEmoji
|
||||
}
|
||||
|
||||
// Network
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "networkBox"
|
||||
caption: qsTr("Network")
|
||||
primaryText: root.networkName
|
||||
icon: root.networkIconPath
|
||||
}
|
||||
|
||||
// Fees
|
||||
SignInfoBox {
|
||||
Layout.fillWidth: true
|
||||
Layout.bottomMargin: Style.current.bigPadding
|
||||
objectName: "feesBox"
|
||||
caption: qsTr("Fees")
|
||||
primaryText: qsTr("Max. fees on %1").arg(root.networkName)
|
||||
secondaryText: " "
|
||||
enabled: false
|
||||
visible: root.hasFees
|
||||
components: [
|
||||
ColumnLayout {
|
||||
spacing: 2
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "fiatFeesText"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "%1 %2".arg(formatBigNumber(root.fiatFees)).arg(root.currentCurrency)
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
loading: root.feesLoading
|
||||
customColor: root.enoughFundsForFees ? Theme.palette.directColor1 : Theme.palette.dangerColor1
|
||||
}
|
||||
StatusTextWithLoadingState {
|
||||
objectName: "cryptoFeesText"
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: "%1 ETH".arg(formatBigNumber(root.cryptoFees))
|
||||
horizontalAlignment: Text.AlignRight
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
customColor: root.enoughFundsForFees ? Theme.palette.baseColor1 : Theme.palette.dangerColor1
|
||||
loading: root.feesLoading
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -39,15 +39,15 @@ Item {
|
|||
anchors.fill: mainImage
|
||||
active: !mainImage.visible
|
||||
sourceComponent: StatusRoundedComponent {
|
||||
id: imageWrapper
|
||||
color: Theme.palette.primaryColor3
|
||||
StatusIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.current.padding
|
||||
anchors.fill: imageWrapper
|
||||
anchors.margins: imageWrapper.width / 4.5
|
||||
color: Theme.palette.primaryColor1
|
||||
icon: "dapp"
|
||||
}
|
||||
}
|
||||
}
|
||||
} }
|
||||
|
||||
layer.enabled: true
|
||||
layer.effect: OpacityMask {
|
||||
|
@ -72,7 +72,7 @@ Item {
|
|||
|
||||
StatusRoundIcon {
|
||||
id: badge
|
||||
width: (root.width / 2) - Style.current.padding
|
||||
width: root.width / 3.6
|
||||
height: width
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import QtQuick 2.15
|
||||
import QtQuick.Layouts 1.15
|
||||
import QtGraphicalEffects 1.15
|
||||
|
||||
import StatusQ.Controls 0.1
|
||||
import StatusQ.Core 0.1
|
||||
import StatusQ.Core.Theme 0.1
|
||||
|
||||
import utils 1.0
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
|
@ -14,40 +18,60 @@ Rectangle {
|
|||
color: "transparent"
|
||||
radius: 8
|
||||
|
||||
implicitHeight: contentScrollView.implicitHeight + (2 * contentText.anchors.margins)
|
||||
implicitHeight: d.expanded ? contentText.implicitHeight + (2 * contentText.anchors.margins) :
|
||||
Math.min(contentText.implicitHeight + (2 * contentText.anchors.margins), 200)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: contentScrollView.enabled || !enabled ? undefined : Qt.PointingHandCursor
|
||||
enabled: contentScrollView.height < contentScrollView.contentHeight
|
||||
|
||||
onClicked: {
|
||||
contentScrollView.enabled = !contentScrollView.enabled
|
||||
HoverHandler {
|
||||
id: hoverHandler
|
||||
target: root
|
||||
}
|
||||
z: contentScrollView.z + 1
|
||||
}
|
||||
|
||||
StatusScrollView {
|
||||
id: contentScrollView
|
||||
anchors.fill: parent
|
||||
|
||||
contentWidth: availableWidth
|
||||
contentHeight: contentText.contentHeight
|
||||
|
||||
padding: 0
|
||||
|
||||
enabled: false
|
||||
|
||||
StatusBaseText {
|
||||
id: contentText
|
||||
objectName: "textContent"
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 20
|
||||
|
||||
width: contentScrollView.availableWidth
|
||||
|
||||
text: root.payloadToDisplay
|
||||
font.pixelSize: Style.current.additionalTextSize
|
||||
lineHeightMode: Text.FixedHeight
|
||||
lineHeight: 18
|
||||
|
||||
wrapMode: Text.WrapAnywhere
|
||||
|
||||
StatusFlatButton {
|
||||
objectName: "expandButton"
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
icon.name: d.expanded ? "collapse" : "expand"
|
||||
icon.color: hovered ? Theme.palette.directColor1 : Theme.palette.baseColor1
|
||||
hoverColor: "transparent"
|
||||
visible: d.canExpand && hoverHandler.hovered
|
||||
onClicked: {
|
||||
d.expanded = !d.expanded
|
||||
}
|
||||
}
|
||||
|
||||
layer.enabled: !d.expanded && d.canExpand
|
||||
layer.effect: OpacityMask {
|
||||
maskSource: Rectangle {
|
||||
width: root.width
|
||||
height: root.height
|
||||
gradient: Gradient {
|
||||
orientation: Gradient.Vertical
|
||||
GradientStop { position: 0.0 }
|
||||
GradientStop { position: (root.height - 60) / root.height }
|
||||
GradientStop { position: 1; color: "transparent" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
readonly property int maxContentHeight: 350
|
||||
property bool expanded: false
|
||||
property bool canExpand: contentText.implicitHeight > maxContentHeight
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,6 @@ PairWCModal 1.0 PairWCModal.qml
|
|||
DAppsListPopup 1.0 DAppsListPopup.qml
|
||||
ConnectDAppModal 1.0 ConnectDAppModal.qml
|
||||
ConnectionStatusTag 1.0 ConnectionStatusTag.qml
|
||||
DAppRequestModal 1.0 DAppRequestModal.qml
|
||||
DAppSignRequestModal 1.0 DAppSignRequestModal.qml
|
||||
DAppsUriCopyInstructionsPopup 1.0 DAppsUriCopyInstructionsPopup.qml
|
||||
RoundImageWithBadge 1.0 RoundImageWithBadge.qml
|
||||
|
|
|
@ -6,7 +6,6 @@ QObject {
|
|||
id: root
|
||||
|
||||
required property var controller
|
||||
|
||||
/// \c dappsJson serialized from status-go.wallet.GetDapps
|
||||
signal dappsListReceived(string dappsJson)
|
||||
signal userAuthenticated(string topic, string id, string password, string pin)
|
||||
|
|
Loading…
Reference in New Issue