1.0.9 • Published 1 year ago

scuffed-abi v1.0.9

Weekly downloads
-
License
MIT
Repository
github
Last release
1 year ago

Scuffed ABI

Package for modifying ABI encoded data. Mostly useful for testing failure cases of ABI decoders.

Given an ethers Contract object, you can build a scuffed contract using the function getScuffedContract.

This will return an object whose keys are the contract's function and which take the same input parameters as their associated functions.

Calling one of these functions will return an object mirroring the structure of the input parameters, with a ReplaceableOffsets object for each value's head, tail or length, as well as parameters for all nested values. See types for more information on data types.

The ReplaceableOffsets type has a function replace which allows you to replace a value after it's been encoded.

Example

Suppose we have the function:

struct SignedTransfer {
  address to;
  uint256 value;
  bytes signature;
}

function validateSignatures(SignedTransfer[] calldata transfers) external;

Then we can use scuffed abi like so:

const scuffed = getScuffedContract(contract);
const scuffedFnCall = scuffed.validateSignatures([{
  to: wallet.address,
  value: 1000,
  signature: sign(defaultAbiCoder.encode(['address', 'bytes'], [wallet.address, 1000]))
}]);
// Modify the offset to the `transfers` array
scuffedFnCall.transfers.head.replace(0x20)
// Modify the length of the signature in the first transfer
scuffedFnCall.transfers[0].signature.length.replace(0x40)
// Modify the offset to the first transfer
scuffedFnCall.transfers[0].head.replace(0)
// Modify `value`
scuffedFnCall.transfers[0].value.replace(500)
// Encode the function calldata
const data = scuffedFnCall.encode()

Types

type ReplaceableOffsets = {
  relative: number;   // position of the parameter relative to its parent
  absolute: number;   // absolute position of the parameter in the encoded args
  replace: (value: BigNumberish) => string; // replace the value in the encoded args
}

Dynamic values will have:

type DynamicOffsets = {
  head: ReplaceableOffsets;
  tail: ReplaceableOffsets;
}

Arrays and bytes parameters will have an additional length: ReplaceableOffsets field.

Static parameters will simply have the ReplaceableOffsets type without a head or tail.

Example

In the example code above, the scuffedFnCall will be structured as:

{
  encode: () => string // Encode the function call with all updated parameters
  encodeArgs: () => string // Encode the input parameters without the selector
  execute: () => Promise<Transaction> // Execute the transaction with the updated parameters
  call: () => Promise<string> // Call the function with the updated parameters
  transfers: {
    length: ReplaceableOffsets
    head: ReplaceableOffsets
    tail: ReplaceableOffsets
    '0': {
      head: ReplaceableOffsets
      tail: ReplaceableOffsets

      to: ReplaceableOffsets
      value: ReplaceableOffsets

      signature: {
        length: ReplaceableOffsets
        head: ReplaceableOffsets
        tail: ReplaceableOffsets
      }
    }
  }
}
1.0.9

1 year ago

1.0.8

1 year ago

1.0.7

1 year ago

1.0.6

1 year ago

1.0.5

1 year ago

1.0.4

2 years ago

1.0.3

2 years ago

1.0.2

2 years ago

1.0.1

2 years ago

1.0.0

2 years ago