Summary
Add type-safe contract interactions to useWriteContract by inferring function names and argument types from Clarity contract ABIs (as const objects). Users get autocomplete on function names and type-checked named args without importing ClarityValue constructors. Main feature for v1.
ABI source agnostic — works with any ClarityAbi (Clarinet output, Stacks API, @satoshai/abi-cli, inline). Full type inference requires as const; plain ClarityAbi objects still work at runtime without autocomplete.
API
Typed mode (with ABI)
import { abi } from './abis/amm-pool-v2-01';
const { writeContract } = useWriteContract();
writeContract({
abi,
contractAddress: 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM',
contractName: 'amm-pool-v2-01',
functionName: 'swap', // autocompletes only public functions
args: {
'token-x': 'SP...addr.token-x', // TraitReference
'token-y': 'SP...addr.token-y', // TraitReference
'amount': 1000000n, // bigint (uint128)
},
});
Contract config helper
const ammPool = createContractConfig({
abi,
contractAddress: 'SP102V8P0F7JX67ARQ77WEA3D3CFB5XW39REDT0AM',
contractName: 'amm-pool-v2-01',
});
writeContract({ ...ammPool, functionName: 'swap', args: { ... } });
writeContract({ ...ammPool, functionName: 'add-liquidity', args: { ... } });
Untyped mode (backward compatible)
writeContract({
contractAddress: 'SP102V8P...',
contractName: 'amm-pool-v2-01',
functionName: 'swap',
functionArgs: [contractPrincipalCV(...), contractPrincipalCV(...), uintCV(1000000n)],
});
When abi is omitted, the current API works as-is. No breaking change.
Clarity → TypeScript type mapping
| Clarity ABI type |
TypeScript type |
Runtime conversion |
uint128 |
bigint |
uintCV() |
int128 |
bigint |
intCV() |
bool |
boolean |
boolCV() |
principal |
string |
standardPrincipalCV() / contractPrincipalCV() (auto-detected by . presence) |
trait_reference |
`${string}.${string}` |
contractPrincipalCV() |
none |
null |
noneCV() |
{ buffer: { length: N } } |
Uint8Array |
bufferCV() |
{ 'string-ascii': { length: N } } |
string |
stringAsciiCV() |
{ 'string-utf8': { length: N } } |
string |
stringUtf8CV() |
{ optional: T } |
ClarityTypeToTS<T> | null |
someCV() / noneCV() |
{ list: { type: T, length: N } } |
ClarityTypeToTS<T>[] |
listCV() |
{ tuple: [...] } |
{ [name]: ClarityTypeToTS<type> } |
tupleCV() |
{ response: { ok: T, error: E } } |
N/A (output only) |
N/A |
Implementation
1. Type utilities — via clarity-abitype
Use clarity-abitype (v0.4.0, MIT, zero deps, type-only) for:
ExtractAbiFunctionNames<TAbi, 'public'> — public function name union
ExtractAbiFunction<TAbi, TName> — function definition lookup
ClarityAbiArgsToPrimitiveTypes — Clarity types → TS primitives
Add kit-specific types:
TraitReference — `${string}.${string}` template literal
TypedWriteContractVariables<TAbi> — overloaded variables type narrowing args by functionName
2. Runtime converter (src/utils/to-clarity-value.ts)
Thin ~30-40 line function: JS natives → ClarityValues, guided by ABI type descriptor. Direct conversion using @stacks/transactions constructors (uintCV, intCV, boolCV, principalCV, etc.), recursive for tuples/lists/optionals.
Clear error messages on type mismatches:
@satoshai/kit: Argument "amount" expects bigint (uint128), got number
3. Contract config helper (src/utils/create-contract-config.ts)
createContractConfig({ abi, contractAddress, contractName }) — typed spread-able object.
4. Hook changes (use-write-contract.ts)
- When
abi + named args present: iterate ABI function args, call toClarityValue for each in order, pass to @stacks/connect
- When
abi absent: pass functionArgs as-is (current behavior)
5. Exports
Export createContractConfig, TraitReference, and relevant type utilities from src/index.ts.
Dependencies
clarity-abitype — type-only dev dependency for type-level ABI utilities (zero runtime cost, can be replaced with own types if unmaintained)
- No new runtime deps — conversion uses
@stacks/transactions constructors (already a peer dep)
Summary
Add type-safe contract interactions to
useWriteContractby inferring function names and argument types from Clarity contract ABIs (as constobjects). Users get autocomplete on function names and type-checked named args without importing ClarityValue constructors. Main feature for v1.ABI source agnostic — works with any
ClarityAbi(Clarinet output, Stacks API,@satoshai/abi-cli, inline). Full type inference requiresas const; plainClarityAbiobjects still work at runtime without autocomplete.API
Typed mode (with ABI)
Contract config helper
Untyped mode (backward compatible)
When
abiis omitted, the current API works as-is. No breaking change.Clarity → TypeScript type mapping
uint128bigintuintCV()int128bigintintCV()boolbooleanboolCV()principalstringstandardPrincipalCV()/contractPrincipalCV()(auto-detected by.presence)trait_reference`${string}.${string}`contractPrincipalCV()nonenullnoneCV(){ buffer: { length: N } }Uint8ArraybufferCV(){ 'string-ascii': { length: N } }stringstringAsciiCV(){ 'string-utf8': { length: N } }stringstringUtf8CV(){ optional: T }ClarityTypeToTS<T> | nullsomeCV()/noneCV(){ list: { type: T, length: N } }ClarityTypeToTS<T>[]listCV(){ tuple: [...] }{ [name]: ClarityTypeToTS<type> }tupleCV(){ response: { ok: T, error: E } }Implementation
1. Type utilities — via
clarity-abitypeUse
clarity-abitype(v0.4.0, MIT, zero deps, type-only) for:ExtractAbiFunctionNames<TAbi, 'public'>— public function name unionExtractAbiFunction<TAbi, TName>— function definition lookupClarityAbiArgsToPrimitiveTypes— Clarity types → TS primitivesAdd kit-specific types:
TraitReference—`${string}.${string}`template literalTypedWriteContractVariables<TAbi>— overloaded variables type narrowingargsbyfunctionName2. Runtime converter (
src/utils/to-clarity-value.ts)Thin ~30-40 line function: JS natives → ClarityValues, guided by ABI type descriptor. Direct conversion using
@stacks/transactionsconstructors (uintCV,intCV,boolCV,principalCV, etc.), recursive for tuples/lists/optionals.Clear error messages on type mismatches:
3. Contract config helper (
src/utils/create-contract-config.ts)createContractConfig({ abi, contractAddress, contractName })— typed spread-able object.4. Hook changes (
use-write-contract.ts)abi+ namedargspresent: iterate ABI function args, calltoClarityValuefor each in order, pass to@stacks/connectabiabsent: passfunctionArgsas-is (current behavior)5. Exports
Export
createContractConfig,TraitReference, and relevant type utilities fromsrc/index.ts.Dependencies
clarity-abitype— type-only dev dependency for type-level ABI utilities (zero runtime cost, can be replaced with own types if unmaintained)@stacks/transactionsconstructors (already a peer dep)