@droplinked_inc/wallet-connection
v0.4.0
Published
Wallet connection adapters for droplinked (MetaMask, Coinbase, WalletConnect, Phantom). Hardened recover+rewrite of the original @droplinked/wallet-connection.
Readme
@droplinked_inc/wallet-connection
Hardened wallet-connection primitives for droplinked: MetaMask, Coinbase
Wallet, and Phantom. EIP-712 typed-data login with chain + origin +
nonce binding, zod-validated RPC boundaries, no any, no remote ABI
fetches.
This package is a clean rewrite of the original
@droplinked/[email protected] (hostile-published by an external
actor). See THREAT_MODEL.md for the threat scenarios this package
mitigates and the test cases that exercise them.
Install
pnpm add @droplinked_inc/wallet-connectionPeer-ish runtime deps:
viem ^2.21zod ^3.23
Both are direct dependencies; you do not need to install them yourself.
Quick start — EVM login (MetaMask)
import {
EvmConnector,
Chain,
Network,
verifyLoginSignature,
buildSession,
saveSession,
} from '@droplinked_inc/wallet-connection';
const connector = new EvmConnector({
chain: Chain.ETH,
network: Network.MAINNET,
origin: window.location.origin,
});
const { address, signature } = await connector.walletLogin();
// Verify (server-side or client-side):
await verifyLoginSignature({
payload: /* the LoginPayload returned by your server */,
signature,
expectedAddress: address,
expectedChainId: 1,
expectedOrigin: window.location.origin,
});
saveSession(
buildSession({
address,
chainId: 1,
origin: window.location.origin,
signature,
ttlSeconds: 60 * 60 * 8, // 8 hours
}),
);Quick start — Phantom (Solana) login
import { PhantomConnector, Network } from '@droplinked_inc/wallet-connection';
const connector = new PhantomConnector(Network.MAINNET);
const { address, signature } = await connector.walletLogin();ERC-20 transfer
const txHash = await connector.paymentWithToken(
receiverAddress,
1000000n, // amount as bigint
tokenAddress,
);Note: this issues a direct transfer. There is no approve API
exposed — drainer-style allowance flows are not reachable from this
package. See THREAT_MODEL.md §T5.
Custom checkout calldata
The droplinked v3 checkout contract is invoked via
submitRawTransaction() with calldata produced by the droplinked
checkout API. The legacy direct ABI encoder is intentionally removed
(see THREAT_MODEL.md §T7 — remote ABI/address fetch was a single
point of supply-chain compromise).
const txHash = await connector.submitRawTransaction({
to: checkoutContractAddress,
data: serverProducedCalldata,
value: totalPriceWei,
gasLimit: 3_000_000n,
});Security
- All RPC responses are zod-validated. Wallets that return malformed data cause a typed error, not silent corruption.
- Login signatures are EIP-712 typed with chain + origin + nonce + issuedAt + optional expirationTime.
selectMetaMaskProvider()andselectCoinbaseProvider()require the wallet's own self-identification flag. There is no fallback to the umbrellawindow.ethereum.- Nonces use
crypto.getRandomValues()(256 bits). If Web Crypto is unavailable the call throws — there is noMath.random()fallback. - Sessions default to
sessionStorage(cleared on tab close), notlocalStorage. They carry an explicitexpiresAtthatloadSession()enforces.
See THREAT_MODEL.md for the full delta vs. the original v1.0.1 and
the tests that exercise each scenario.
Status
Initial recover + harden. The original public API names are preserved
where feasible; the following changes are deliberate and noted in
THREAT_MODEL.md:
- Chain/Network/ChainWallet are now string-valued enums (was implicit- numeric).
getNetworkProvider(chain, network, address, wallet)is nowgetNetworkProvider({ chain, network, address, wallet, ... }).EVMProvideris nowEvmConnector;SolanaProvideris nowPhantomConnector(constructor signatures changed accordingly).EVMPayment(the free function) is removed; useEvmConnector.submitRawTransaction().- Error classes now extend
Error(regression-fixes try/catch).
License
MIT.
