Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: dynamic array encoding #2174

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

xj894976677
Copy link

Dynamic Array Encoding Fix in Web3j

Problem Statement

The original implementation did not correctly handle dynamic arrays according to Solidity's ABI encoding specification. In Solidity, when using abi.encode() with array parameters, the output includes dynamic offsets pointing to the actual array data.

Example in Solidity

// Solidity contract
function encodeExample(uint256[] memory tokenIds, uint256[] memory amounts) public pure returns (bytes memory) {
    return abi.encode(tokenIds, amounts);
}

When calling this function with:

tokenIds = [1, 2]
amounts = [100, 200, 300]

The encoded output structure should be:

[offset_1][offset_2][array1_length][array1_data...][array2_length][array2_data...]

Issue

The original Web3j implementation was concatenating array data directly without proper offset handling:

// Original problematic implementation
ByteArrayOutputStream concatenatedArrayEncodingBuffer = new ByteArrayOutputStream();
for (Object arrayItem : arrayItems) {
    // Directly writing array data without offsets
    concatenatedArrayEncodingBuffer.write(arrayItemEncoding, 0, arrayItemEncoding.length);
}

Solution

Modified the implementation to follow Solidity's ABI encoding specification:

// Fixed implementation
// 1. Calculate and write offsets in the header
encValues.add(BigInteger.valueOf(headSize + dynamicDataSize));

// 2. Store dynamic data separately
ByteArrayOutputStream dynamicBuffer = new ByteArrayOutputStream();
// Write array length
byte[] lengthBytes = Numeric.toBytesPadded(BigInteger.valueOf(arrayItems.size()), 32);
dynamicBuffer.write(lengthBytes, 0, lengthBytes.length);
// Write array elements
for (Object arrayItem : arrayItems) {
    byte[] itemBytes = Numeric.toBytesPadded(convertToBigInt(arrayItem), 32);
    dynamicBuffer.write(itemBytes, 0, itemBytes.length);
}

Impact

  • Ensures compatibility with Solidity's abi.encode() function
  • Fixes signature verification issues in contracts using EIP-712
  • Correctly handles multiple dynamic arrays in structured data

This change aligns Web3j's implementation with Ethereum's ABI specification for dynamic array encoding.

joseph.xiang added 2 commits March 26, 2025 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant