0

I read this article on sorting an array off-chain using event listeners, but my array doesn't appear to be sorted in time when the array is called in typescript.

This is my contract:

pragma solidity 0.8.4;
pragma experimental ABIEncoderV2;


contract Test  {


    uint256[] unsortedArr;

    uint256[] sortedArr;

    event sort(uint256[]);


    function addElement(uint256 element) public {
        unsortedArr.push(element);
    }

    function sortOffChain() public  returns (uint[] memory)
    {
    /*On the backend, the algorithm would look something like this -

    *event listener listening for sort()
    *calls sort function in typescript upon getting triggered
    *calls getSortedData() function with returned value of sort()
*/
        emit sort(unsortedArr);
        // I want sortedArr below to be sorted by the time the return is called
        return sortedArr;
    }
    
    function getSortedData(uint256[] memory sortedData) public 
    {
        sortedArr = sortedData;
    }


// for typescript test
function getUnsortedArr() public view returns (uint256[] memory) {
        return unsortedArr;
    }

function getSortedArr() public view returns (uint256[] memory) {
    return sortedArr;
}
}

This is what the event listener looks like in TypeScript:

async function main() {
;

// deploying
  const Test = await hre.ethers.getContractFactory("Test");
  const test = await Test.deploy();
  await test.deployed();
  console.log("Test deployed to", test.address);
// add elements to array
  await test.addElement(5);
  await test.addElement(3);
  await test.addElement(7);
  await test.addElement(2);
  await test.addElement(1);
  await test.addElement(9);
// event listener
const OffChainResult = await test.sortOffChain();
test.on("sort", (arr: []) => {
  let arrayForSort = [...arr];
  const sortedArr = arrayForSort.sort((n1: number,n2 : number) => n1 - n2);
  console.log("array sorted");
  test.getSortedData(sortedArr);
  console.log("getSortedData completed");
}
);
console.log("output of getSortedData:");
console.log(OffChainResult);

This is what comes out in the terminal when I run the script:

Test deployed to 0x5FbDB2315678afecb367f032d93F642f64180aa3
output of getSortedData:
{
  hash: '0x40eeca2775e29300e51f3a067c99195f0cf33ee0aac73eaeaf05d826b41c3d4c',
  type: 2,
  accessList: [],
  blockHash: '0xd952eb1b086de3b1ee213fff01b464925670bc6d7e515ac3f7dad3b732471857',
  blockNumber: 8,
  transactionIndex: 0,
  confirmations: 1,
  from: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  gasPrice: BigNumber { value: "1346048670" },
  maxPriorityFeePerGas: BigNumber { value: "1000000000" },
  maxFeePerGas: BigNumber { value: "1692097340" },
  gasLimit: BigNumber { value: "29021272" },
  to: '0x5FbDB2315678afecb367f032d93F642f64180aa3',
  value: BigNumber { value: "0" },
  nonce: 7,
  data: '0xb8dbac2c',
  r: '0x621282eec4ac159b052250faa62aa5e954510ba91e841d3477bf0228ecf952d9',
  s: '0x7d36e86d604b58006dd918efc52babd3f3e61dd9f80e36fa2e3e8a9a03fe5298',
  v: 1,
  creates: null,
  chainId: 31337,
  wait: [Function (anonymous)]
}
array sorted
getSortedData completed

There are two issues: (1) getSortedData() which is called by sortOffChain() returns a value before the event listener gets a chance to sort the array and set sortedArr to the right value and (2) even if the array isn't sorted, sortOffChain() should return an empty array, not whatever the console output for `OffChain.

Is this just an issue with how I made the event listener? Do I need to put the lines of code in a different order? Also, what is the thing that the console output for OffChainResult.

I've also heard that the sorted array that is to be given to the smart contract can't be validated. How do I ensure that it is?

1 Answer 1

0

I had to go through your code and I tested on my end too, and frankly, I learned a lot from this post. So to begin with, your contract is a little buggy. Since you want to catch the event, you don't need to return anything. Even if you do, you need to use view in your function. I modified the contract and it looks like this:

//SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

contract Sort {
    uint256[] unsortedArr;
    uint256[] sortedArr;

    event sort(uint256[]);

    function addElement(uint256 element) public {
        unsortedArr.push(element);
    }

    function sortOffChain() public {
        emit sort(unsortedArr);
    }

    function getSortedData(uint256[] memory sortedData) public {
        sortedArr = sortedData;
    }

    // for typescript test
    function getUnsortedArr() public view returns (uint256[] memory) {
        return unsortedArr;
    }

    function getSortedArr() public view returns (uint256[] memory) {
        return sortedArr;
    }
}

Moving on, you need to change the method to change the process of catching the event. I might have written the code differently. You can fix that on your end. It will be like this:

  function get1DArray(arr: any) {
    return arr.join().split(",");
  }

  it("Event get", async () => {
    let data = await sort.sortOffChain();
    let receipt = await data.wait();
    let finalEvent = receipt.events?.find((event) => event.event === "sort");
    let unsortedArray = get1DArray(finalEvent?.args);
    console.log("Unsorted Array: ", unsortedArray);

    const sortedArray = unsortedArray.sort((n1: number, n2: number) => n1 - n2);
    console.log("Sorted Array: ", sortedArray);

    console.log(
      "Previous Sorted array in contract: ",
      await sort.getSortedArr()
    );

    await sort.getSortedData(sortedArray);
    console.log(
      "New Sorted array in contract: ",
      (await sort.getSortedArr()).toString()
    );
  });

It would be best if you had this function get1DArray since args returns an array of an array. You will get a sorted array sorted off-chain using this.

1
  • This has worked great for me here, but I'm having trouble implementing this same off-chain computation with other off-chain computations. I tried using what you wrote here for another smart contract meant to track defaults, but I'm getting mixed results. Here is my problem. Could you also try taking a look at this problem as well?
    – HeeeeSark
    Jul 30, 2022 at 4:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.