Skip to content
Merged
Show file tree
Hide file tree
Changes from 47 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
5805196
WIP: poc-signer
claudiovb Dec 2, 2025
8a4dc0c
WIP: poc-signer
claudiovb Dec 3, 2025
e04a862
add ISignerEvm
claudiovb Dec 4, 2025
4c77e8c
add ISignerEvm
claudiovb Dec 4, 2025
4f18ce8
feat: add ledger signer evm
sontuphan Dec 8, 2025
2bd8427
fix: lint standardjs
sontuphan Dec 8, 2025
c00a22e
fix: add deps
sontuphan Dec 8, 2025
fc31010
fix: remote master node in bip44 derivation path in ledger signer
sontuphan Dec 9, 2025
6dbfe99
fix: add private async connect
sontuphan Dec 16, 2025
5af6f0a
Merge pull request #1 from sontuphan/poc-ledger-signer
claudiovb Dec 23, 2025
3a6b289
fix signer
claudiovb Dec 23, 2025
1734267
add safety checks to ledger signer
claudiovb Dec 23, 2025
bb9f608
fix sendTransaction
claudiovb Dec 23, 2025
ccdcfb9
fix derive function
claudiovb Dec 23, 2025
c4a879f
Merge branch 'tetherto:main' into poc-signer
claudiovb Dec 24, 2025
db2ff81
clean up for publishing
claudiovb Dec 24, 2025
f921284
update readme code
claudiovb Dec 24, 2025
f9fb077
refactor ledger submodule
claudiovb Dec 24, 2025
d937ab8
remove not used signer config object
claudiovb Dec 25, 2025
123e995
add missing method to ledger signer
claudiovb Dec 26, 2025
b2d6660
fix: bump dmk versions, fix minor bugs, autogen signer types
sontuphan Feb 12, 2026
d03a102
Merge pull request #3 from sontuphan/fix/poc-signer
claudiovb Feb 12, 2026
b901da8
fix: remove isActive and update ledger dispose
sontuphan Apr 8, 2026
9372233
Plain object signers fix, update packages
claudiovb Apr 8, 2026
8c12540
Merge changes
claudiovb Apr 10, 2026
cbc2d6c
Merge changes
claudiovb Apr 17, 2026
84b8cb1
fixes
claudiovb Apr 17, 2026
86d0061
Update src/signers/seed-signer-evm.js
claudiovb Apr 21, 2026
4b03dc9
Update src/signers/ledger-signer-evm.js
claudiovb Apr 21, 2026
997cbb5
defaults in the description not in brackets
claudiovb Apr 21, 2026
9f94876
Merge branch 'poc-signer' of github.com:claudiovb/wdk-wallet-evm into…
claudiovb Apr 21, 2026
cefe0a9
Small JSDOC fixes
claudiovb Apr 21, 2026
a213e11
Split test for signers & ISignerEVM contract fullfilment
claudiovb Apr 21, 2026
6a378b8
Merge with new updates
claudiovb Apr 29, 2026
bf11299
Fix JSDOCS issues
claudiovb May 4, 2026
3a041e0
Fix Ledger signing and unneeded guard clauses
claudiovb May 4, 2026
65576ed
Fix tests comments
claudiovb May 4, 2026
432aac7
Update types
claudiovb May 4, 2026
e615962
Update types and JSdocs small polishes
claudiovb May 4, 2026
109ba85
merge changes from main
claudiovb Jun 17, 2026
d979205
refactor to conform with new wdk-wallet implementation
claudiovb Jun 17, 2026
eb47d2c
fix bug from ricardo comment
claudiovb Jun 18, 2026
d81a6d0
update not needed tests and jsdoc definitions
claudiovb Jun 18, 2026
aeb52e3
minor fixes
claudiovb Jun 18, 2026
64ea4b9
update derive so its compatible with baseClass, refactor for better d…
claudiovb Jun 18, 2026
03cba9d
update package to published wdk-wallet version
claudiovb Jun 19, 2026
13cf4ac
don't pin peerdeps to avoid issue on consumers that use ledger instal…
claudiovb Jun 19, 2026
e4a0235
merge with changes on main
claudiovb Jun 19, 2026
3a2e0cd
address Ricardo's comments
claudiovb Jun 19, 2026
cfe141e
update with main
claudiovb Jun 24, 2026
a264337
update to to be nullable for allowing sc creation
claudiovb Jun 25, 2026
0dcd6a8
add test to validate smart contract creation
claudiovb Jun 25, 2026
49a3f3e
remove ledger from this branch
claudiovb Jun 25, 2026
74b3ea9
add fromPrivateKey static method to EVM
claudiovb Jun 25, 2026
6bc4b85
update wdk-wallet dep type
claudiovb Jun 26, 2026
815d022
update JSDOC
claudiovb Jun 26, 2026
853525f
remove useless guard on getAddress
claudiovb Jun 26, 2026
79c41bd
remove stale ts text
claudiovb Jun 26, 2026
ad224c6
update wdk-wallet to latest version
claudiovb Jun 29, 2026
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
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
node_modules
coverage
.vscode
.DS_Store
.vscode
329 changes: 305 additions & 24 deletions README.md

Large diffs are not rendered by default.

2,234 changes: 1,971 additions & 263 deletions package-lock.json

Large diffs are not rendered by default.

31 changes: 29 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,35 @@
"test:integration:coverage": "cross-env NODE_OPTIONS=--experimental-vm-modules jest tests/integration --coverage"
},
"dependencies": {
"@noble/curves": "1.9.2",
"@noble/hashes": "1.8.0",
"@noble/secp256k1": "2.2.3",
"@tetherto/wdk-wallet": "1.0.0-beta.11",
"@tetherto/wdk-failover-provider": "1.0.0-beta.2",
"@tetherto/wdk-wallet": "1.0.0-beta.8",
"bare-node-runtime": "^1.1.4",
"bip39": "3.1.0",
"ethers": "6.14.4",
"sodium-universal": "5.0.1"
},
"peerDependencies": {
"@ledgerhq/device-management-kit": "^1.3.0",
"@ledgerhq/device-signer-kit-ethereum": "^1.10.0",
"@ledgerhq/device-transport-kit-web-hid": "^1.2.3",
"rxjs": "^7.8.2"
},
"peerDependenciesMeta": {
"@ledgerhq/device-management-kit": {
"optional": true
},
"@ledgerhq/device-signer-kit-ethereum": {
"optional": true
},
"@ledgerhq/device-transport-kit-web-hid": {
"optional": true
},
"rxjs": {
"optional": true
}
},
"devDependencies": {
"@nomicfoundation/hardhat-ethers": "3.0.9",
"cross-env": "7.0.3",
Expand All @@ -61,6 +80,14 @@
"bare": "./bare.js",
"default": "./index.js"
},
"./signers": {
Comment thread
Davi0kProgramsThings marked this conversation as resolved.
"types": "./types/src/signers/index.d.ts",
"default": "./src/signers/index.js"
},
"./signers/ledger": {
"types": "./types/src/signers/ledger-signer-evm.d.ts",
"default": "./src/signers/ledger-signer-evm.js"
},
"./package": {
"default": "./package.json"
}
Expand Down
9 changes: 5 additions & 4 deletions src/memory-safe/hd-node-wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,15 @@ export default class MemorySafeHDNodeWallet extends BaseWallet {
}

const { IR, IL } = serI(index, this.chainCode, this.publicKey, this.privateKeyBuffer)
const childPriv = new Uint8Array(this.privateKeyBuffer)
Comment thread
Davi0kProgramsThings marked this conversation as resolved.

const overflow = addToPrivateKey(this.privateKeyBuffer, IL)
const overflow = addToPrivateKey(childPriv, IL)

if (overflow || compareWithCurveOrder(this.privateKeyBuffer) >= 0) {
subtractCurveOrderFromPrivateKey(this.privateKeyBuffer)
if (overflow || compareWithCurveOrder(childPriv) >= 0) {
subtractCurveOrderFromPrivateKey(childPriv)
}

const ki = new MemorySafeSigningKey(this.privateKeyBuffer)
const ki = new MemorySafeSigningKey(childPriv)

return new MemorySafeHDNodeWallet(_guard, ki, this.fingerprint, hexlify(IR),
path, index, this.depth + 1, this.mnemonic, this.provider)
Expand Down
7 changes: 4 additions & 3 deletions src/memory-safe/signing-key.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ export default class MemorySafeSigningKey extends SigningKey {
}

dispose () {
sodium_memzero(this._privateKeyBuffer)

this._privateKeyBuffer = undefined
if (this._privateKeyBuffer) {

@Davi0kProgramsThings Davi0kProgramsThings Jul 7, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for the 'dispose' method to be idempotent. By definition, after disposing an object users should expect all methods to have undefined behavior which basically includes anything. We should just guarantee that such undefined behavior doesn't include any unsafe operations but since the private key is not available anymore this is not a possible scenario. These changes are not a mistake but we can safely revert them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd keep the guard, and I don't think this is about post-dispose undefined behavior... it's about disposal itself being safe to run from multiple owners. WalletManager.dispose() disposes all accounts (each of which disposes its signer) and then loops over the registered signers disposing them again. For a named non-derivable signer, the account's signer is the registered signer object, so manager.dispose() calls dispose() twice on the same object by design. I reproduced this: without the guard the second call crashes with sodium_memzero: buf must be a typed array. So reverting doesn't just make user double-dispose UB; it makes our own teardown path throw.

More generally, idempotent disposal is the standard contract precisely because cleanup graphs overlap: .NET's IDisposable mandates it ("must ignore all calls after the first one") and TC39's DisposableStack.dispose() is specified as a no-op when already disposed. The guard is two lines; I'd rather keep teardown order-independent than make every owner coordinate who disposes first. I also added double-dispose tests to both signer suites in #95 to lock the contract in.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, this makes sense.

I have a suggestion for a different improvement. I'll post it here though, since i don't think there is a better place. Since the 'dispose' method now exists in multiple interfaces and abstract classes i.e., 'WalletManager', 'IWalletAccount', 'ISigner', it would be better to create an ad-hoc type for it and make them implement it. Your mention to .NET's IDisposable made me remember this improvement i thought about some weeks ago. Feel free to add these changes to wdk-wallet pr#52.

// /src/disposable.js
/** @interface */
export class IDisposable {
  /**
   * Disposes the object along with all its data (cleaning up any sensitive field from memory).
   */
  dispose () {
    throw new NotImplementedError('dispose()')
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea, done in wdk-wallet#52: added src/disposable.js with IDisposable as you spec'd, ISigner now extends it (its own dispose stub is gone), and IWalletAccount/WalletManager implement it. The concrete signers and accounts needed no changes, they already implement dispose() and inherit the contract through the interface chain.

sodium_memzero(this._privateKeyBuffer)
this._privateKeyBuffer = undefined
}
}
}
22 changes: 22 additions & 0 deletions src/signers/index.js
Comment thread
Davi0kProgramsThings marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Copyright 2024 Tether Operations Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// src/signers/index.js
/**
* Barrel exports for EVM signers.
*
* - `SeedSignerEvm`: derives accounts from a BIP-39 seed (BIP-44 path).
* - `PrivateKeySignerEvm`: memory-safe wrapper around a raw private key.
*/
export { default, default as SeedSignerEvm } from './seed-signer-evm.js'
export { default as PrivateKeySignerEvm } from './private-key-signer-evm.js'
Loading