Skip to main content

    Signature Format Rules

    The canonical signature follows strict formatting rules:
    1. Function name - Exact name from ABI
    2. Opening parenthesis - No space after name
    3. Parameter types - Only types, no names
    4. Comma-separated - No spaces around commas
    5. Closing parenthesis - No trailing content
    // Correct canonical signature
    "transfer(address,uint256)"
    
    // WRONG - includes parameter names
    "transfer(address to, uint256 amount)"
    
    // WRONG - has spaces
    "transfer(address, uint256)"
    
    // WRONG - includes return type
    "transfer(address,uint256) returns (bool)"
    

    Usage Examples

    Basic Signature

    import { Function } from 'tevm'
    
    const balanceOfFn = new Function({
      type: "function",
      name: "balanceOf",
      inputs: [{ type: "address", name: "owner" }],
      outputs: [{ type: "uint256", name: "balance" }]
    })
    
    console.log(balanceOfFn.getSignature())  // "balanceOf(address)"
    

    No Parameters

    import { Function } from 'tevm'
    
    const totalSupplyFn = new Function({
      type: "function",
      name: "totalSupply",
      inputs: [],
      outputs: [{ type: "uint256" }]
    })
    
    console.log(totalSupplyFn.getSignature())  // "totalSupply()"
    

    Complex Parameter Types

    import { Function } from 'tevm'
    
    const swapFn = new Function({
      type: "function",
      name: "swap",
      inputs: [
        { type: "uint256[]", name: "amounts" },
        { type: "address[]", name: "path" },
        {
          type: "tuple",
          name: "params",
          components: [
            { type: "uint256", name: "deadline" },
            { type: "address", name: "to" }
          ]
        }
      ]
    })
    
    console.log(swapFn.getSignature())
    // "swap(uint256[],address[],(uint256,address))"
    

    Tuple Arrays

    import { Function } from 'tevm'
    
    const batchTransferFn = new Function({
      type: "function",
      name: "batchTransfer",
      inputs: [
        {
          type: "tuple[]",
          name: "transfers",
          components: [
            { type: "address", name: "to" },
            { type: "uint256", name: "amount" }
          ]
        }
      ]
    })
    
    console.log(batchTransferFn.getSignature())
    // "batchTransfer((address,uint256)[])"
    

    Computing Selector from Signature

    import { Function } from 'tevm'
    import { Keccak256 } from 'tevm'
    
    const transferFn = new Function({
      type: "function",
      name: "transfer",
      inputs: [
        { type: "address", name: "to" },
        { type: "uint256", name: "amount" }
      ]
    })
    
    // Get signature
    const signature = transferFn.getSignature()
    // "transfer(address,uint256)"
    
    // Hash to get selector
    const hash = Keccak256.hash(signature)
    const selector = hash.slice(0, 10)
    console.log(selector)  // "0xa9059cbb"
    
    // Or use getSelector() directly
    console.log(transferFn.getSelector())  // "0xa9059cbb"
    

    Type-Safe Signatures

    TypeScript can infer the exact signature type:
    import { Function } from 'tevm'
    
    const transferFn = new Function({
      type: "function",
      name: "transfer",
      inputs: [
        { type: "address", name: "to" },
        { type: "uint256", name: "amount" }
      ]
    } as const)
    
    const signature = transferFn.getSignature()
    //    ^-- Type: "transfer(address,uint256)"
    

    Signature Comparison

    Signatures are used to identify function uniqueness:
    import { Function } from 'tevm'
    
    const fn1 = new Function({
      type: "function",
      name: "transfer",
      inputs: [
        { type: "address", name: "to" },
        { type: "uint256", name: "amount" }
      ]
    })
    
    const fn2 = new Function({
      type: "function",
      name: "transfer",
      inputs: [
        { type: "address", name: "recipient" },
        { type: "uint256", name: "value" }
      ]
    })
    
    // Same signature despite different parameter names
    console.log(fn1.getSignature() === fn2.getSignature())  // true
    console.log(fn1.getSignature())  // "transfer(address,uint256)"
    

    Human-Readable Format

    For display purposes, you may want a human-readable format:
    import { Function } from 'tevm'
    
    const transferFn = new Function({
      type: "function",
      name: "transfer",
      inputs: [
        { type: "address", name: "to" },
        { type: "uint256", name: "amount" }
      ],
      outputs: [{ type: "bool", name: "success" }]
    })
    
    // Canonical signature (for hashing)
    const canonical = transferFn.getSignature()
    console.log(canonical)  // "transfer(address,uint256)"
    
    // Human-readable format (manual construction)
    const readable = `function ${transferFn.name}(${transferFn.inputs.map(p => `${p.type} ${p.name}`).join(', ')}) returns (${transferFn.outputs.map(p => p.type).join(', ')})`
    console.log(readable)
    // "function transfer(address to, uint256 amount) returns (bool)"
    

    Fixed vs Dynamic Arrays

    Array notation in signatures:
    import { Function } from 'tevm'
    
    const fn = new Function({
      type: "function",
      name: "process",
      inputs: [
        { type: "uint256[]", name: "dynamic" },      // Dynamic array
        { type: "uint256[3]", name: "fixed" },       // Fixed array
        { type: "bytes", name: "dynamicBytes" },     // Dynamic bytes
        { type: "bytes32", name: "fixedBytes" }      // Fixed bytes
      ]
    })
    
    console.log(fn.getSignature())
    // "process(uint256[],uint256[3],bytes,bytes32)"
    

    Error Handling

    import { Function } from 'tevm'
    
    try {
      const fn = new Function({
        type: "function",
        name: "",  // Invalid: empty name
        inputs: []
      })
      fn.getSignature()
    } catch (error) {
      console.error("Invalid function definition")
    }
    

    See Also

    • getSelector - Get 4-byte selector from signature
    • encodeParams - Encode function calldata
    • format - Format ABI item to signature with parameter names