Skip to content

Commit

Permalink
Merge branch 'main' into fix/CON-522
Browse files Browse the repository at this point in the history
  • Loading branch information
kantorcodes authored Nov 25, 2024
2 parents 10eb1c5 + 646a2ef commit c56a3e0
Show file tree
Hide file tree
Showing 15 changed files with 2,338 additions and 475 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,6 @@ jobs:
test-script: npm run test

- name: Upload results to Codecov
uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4.6.0
uses: codecov/codecov-action@5c47607acb93fed5485fdbf7232e8a31425f672a # v5.0.2
with:
token: ${{ secrets.CODECOV_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ dist
*.sw[a-z]
**/.idea
.docusaurus**
.DS_Store
.DS_Store
coverage
146 changes: 137 additions & 9 deletions demos/react-dapp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
PublicKey,
TransactionId,
TransferTransaction,
AccountCreateTransaction,
KeyList,
} from '@hashgraph/sdk'
import { SessionTypes, SignClientTypes } from '@walletconnect/types'

Expand All @@ -26,7 +28,9 @@ import {
transactionToBase64String,
SignAndExecuteQueryParams,
ExecuteTransactionParams,
} from '@hashgraph/hedera-wallet-connect'
base64StringToUint8Array,
verifySignerSignature,
} from '../../../dist'

import React, { useEffect, useMemo, useState } from 'react'
import Modal from './components/Modal'
Expand Down Expand Up @@ -56,6 +60,7 @@ const App: React.FC = () => {
const [amount, setAmount] = useState('')
const [message, setMessage] = useState('')
const [publicKey, setPublicKey] = useState('')
const [signMethod, setSignMethod] = useState<'connector' | 'signer'>('connector')
const [selectedTransactionMethod, setSelectedTransactionMethod] = useState(
'hedera_executeTransaction',
)
Expand All @@ -65,6 +70,10 @@ const App: React.FC = () => {
const [isModalLoading, setIsModalLoading] = useState<boolean>(false)
const [modalData, setModalData] = useState<any>(null)

// Multi-signature account states
const [publicKeyInputs, setPublicKeyInputs] = useState<string[]>([''])
const [threshold, setThreshold] = useState<number>(1)

useEffect(() => {
const state = JSON.parse(localStorage.getItem('hedera-wc-demos-saved-state') || '{}')
if (state) {
Expand Down Expand Up @@ -183,6 +192,31 @@ const App: React.FC = () => {
})
}

const handleSignMessageThroughSigner = async () => {
modalWrapper(async () => {
if (!selectedSigner) throw new Error('Selected signer is required')
const params: SignMessageParams = {
signerAccountId: 'hedera:testnet:' + selectedSigner.getAccountId().toString(),
message,
}

const buffered = btoa(params.message)
const base64 = base64StringToUint8Array(buffered)

const signResult = await (selectedSigner as DAppSigner).sign(
[base64]
)
const accountPublicKey = PublicKey.fromString(publicKey)
const verifiedResult = verifySignerSignature(params.message, signResult[0], accountPublicKey)
console.log('SignatureMap: ', signResult)
console.log('Verified: ', verifiedResult)
return {
signatureMap: signResult,
verified: verifiedResult,
}
})
}

// 4. hedera_signAndExecuteQuery
const handleExecuteQuery = () => {
modalWrapper(async () => {
Expand Down Expand Up @@ -239,6 +273,36 @@ const App: React.FC = () => {
return { transaction: transactionSigned }
}

// Create multi-signature account
const handleCreateMultisigAccount = async () => {
// Fetch public keys from mirror node for each account
const fetchPublicKey = async (accountId: string) => {
const response = await fetch(
`https://testnet.mirrornode.hedera.com/api/v1/accounts/${accountId}`
)
const data = await response.json()
return data.key.key
}

const publicKeys = await Promise.all(
publicKeyInputs.filter(id => id).map(accountId => fetchPublicKey(accountId))
)

console.log('Public keys: ', publicKeys)

const transaction = new AccountCreateTransaction()
.setKey(new KeyList(publicKeys.map((key) => PublicKey.fromString(key)), threshold))
.setInitialBalance(new Hbar(0))
.setAccountMemo('Multisig Account')

const frozen = await transaction.freezeWithSigner(selectedSigner!)
const result = await frozen.executeWithSigner(selectedSigner!)
console.log('Result: transaction completed', result)
const receipt = await result.getReceiptWithSigner(selectedSigner!)
console.log('Receipt: ', receipt)
return receipt;
}

/**
* Session management methods
*/
Expand Down Expand Up @@ -454,13 +518,17 @@ const App: React.FC = () => {
<div>
<fieldset>
<legend>3. hedera_signMessage</legend>
<AccountSelector
accounts={signers.map((signer) => signer.getAccountId())}
selectedAccount={selectedSigner?.getAccountId() || null}
onSelect={(accountId) =>
setSelectedSigner(dAppConnector?.getSigner(accountId)!)
}
/>
<label>
Sign Method:
<select
value={signMethod}
onChange={(e) => setSignMethod(e.target.value as 'connector' | 'signer')}
className="mb-2"
>
<option value="connector">Sign with Connector</option>
<option value="signer">Sign with Signer</option>
</select>
</label>
<label>
Message:
<input value={message} onChange={(e) => setMessage(e.target.value)} required />
Expand All @@ -475,7 +543,10 @@ const App: React.FC = () => {
</label>
<p>The public key for the account is used to verify the signed message</p>
</fieldset>
<button disabled={disableButtons} onClick={handleSignMessage}>
<button
disabled={disableButtons}
onClick={signMethod === 'connector' ? handleSignMessage : handleSignMessageThroughSigner}
>
Submit to wallet
</button>
</div>
Expand Down Expand Up @@ -600,6 +671,63 @@ const App: React.FC = () => {
<button onClick={handleClearData}>Clear saved data</button>
</div>
</section>
<section>
<div>
<fieldset>
<legend>Create Multi-signature Account</legend>
<AccountSelector
accounts={signers.map((signer) => signer.getAccountId())}
selectedAccount={selectedSigner?.getAccountId() || null}
onSelect={(accountId) =>
setSelectedSigner(dAppConnector?.getSigner(accountId)!)
}
/>
{publicKeyInputs.map((input, index) => (
<div key={index}>
<label>
Account ID {index + 1}:
<input
value={input}
onChange={(e) => {
const newInputs = [...publicKeyInputs]
newInputs[index] = e.target.value
setPublicKeyInputs(newInputs)
}}
placeholder="Enter Account ID"
/>
</label>
{index === publicKeyInputs.length - 1 && (
<button onClick={() => setPublicKeyInputs([...publicKeyInputs, ''])}>
Add Another Account
</button>
)}
</div>
))}
<label>
Threshold:
<input
type="number"
min="1"
max={publicKeyInputs.filter(Boolean).length}
value={threshold}
onChange={(e) => setThreshold(parseInt(e.target.value))}
/>
</label>
</fieldset>
<button
disabled={disableButtons || !publicKeyInputs[0] || threshold < 1}
onClick={() => {
modalWrapper(async () => {
if (!dAppConnector) throw new Error('DAppConnector is required')
if (!selectedSigner) throw new Error('Selected signer is required')
return handleCreateMultisigAccount()
})
}}
>
Create Multisig Account
</button>
</div>
</section>
<Modal title="Send Request" isOpen={isModalOpen} onClose={() => setModalOpen(false)}>
{isModalLoading ? (
<div className="loading">
Expand Down
19 changes: 18 additions & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,28 @@ const config: Config = {
fakeTimers: {
enableGlobally: true,
},
testMatch: ['**/?(*.)+(spec|test).ts?(x)', '!**/DAppConnector.test.ts', '!**/wallet*/**'],
testMatch: ['**/?(*.)+(spec|test).ts?(x)'],
transform: {
'^.+\\.(t|j)sx?$': '@swc/jest',
},
transformIgnorePatterns: ['node_modules/(?!@walletconnect)'],
testEnvironment: 'node',
coverageDirectory: 'coverage',
collectCoverageFrom: [
'src/**/*.{js,ts}',
'!src/**/*.d.ts',
'!src/**/*.test.{js,ts}',
'!src/**/*.config.{js,ts}',
],
coverageReporters: ['text-summary', 'html'],
coverageThreshold: {
global: {
branches: 50,
functions: 50,
lines: 50,
statements: 50,
},
},
}

export default config
39 changes: 18 additions & 21 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "@hashgraph/hedera-wallet-connect",
"version": "1.3.5",
"version": "1.3.7",
"description": "A library to facilitate integrating Hedera with WalletConnect",
"repository": {
"type": "git",
"url": "git+https://github.com/hashgraph/hedera-wallet-connect.git"
},
"main": "./dist/src/index.js",
"types": "./dist/src/index.d.ts",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"author": "Hgraph <[email protected]>",
"keywords": [
"hedera",
Expand All @@ -32,6 +32,7 @@
"husky": "^9.0.6",
"jest": "^29.7.0",
"lint-staged": "^15.1.0",
"long": "^5.2.3",
"lokijs": "^1.5.12",
"nodemon": "^3.0.3",
"prettier": "^3.2.4",
Expand All @@ -54,14 +55,17 @@
"dev:ts-demo": "rimraf dist && npm run build && concurrently --raw \"npm run watch\" \"node scripts/demos/typescript/dev.mjs\"",
"dev:react-demo": "rimraf dist && npm run build && concurrently --raw \"npm run watch\" \"node scripts/demos/react/dev.mjs\"",
"test": "jest",
"test:watch": "jest --watch",
"test:connect": "jest --testMatch '**/DAppConnector.test.ts' --verbose",
"test:signer": "jest --testMatch '**/DAppSigner.test.ts' --verbose",
"prepublishOnly": "rm -Rf dist && npm run build",
"prepare": "husky install",
"prettier:check": "prettier --check ./src/",
"prettier:fix": "prettier --write ./src/",
"prod:docs-docker": "sh docker-run.sh",
"test:sigMap": "jest --testMatch '**/SignatureMapHelpers.test.ts' --verbose"
"test:sigMap": "jest --testMatch '**/SignatureMapHelpers.test.ts' --verbose",
"test:coverage": "jest --coverage",
"test:coverage:html": "jest --coverage --coverageReporters='text-summary' --coverageReporters='html'"
},
"peerDependencies": {
"@hashgraph/sdk": "^2.40.0",
Expand Down
Loading

0 comments on commit c56a3e0

Please sign in to comment.