# Hashing complex structs off-chain

**URL:** https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658
**Category:** TypeScript SDK
**Tags:** testnet, feedback
**Created:** [June 9, 2024, 1:31pm UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658 "2024-06-09T13:31:35Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![theAusicist](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/theausicist/32/1987_2.png) [@theAusicist](https://forum.fuel.network/u/theAusicist)
#### Post date: [June 9, 2024, 1:31pm UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/1 "2024-06-09T13:31:35Z")

</div>

I have a complex struct that I hash on-chain for certain computation. Is there any off-chain way via the TS SDK to hash that struct? I see [keccak256](https://github.com/FuelLabs/fuels-ts/blob/bb5a123f46313f10d444d361fcfcf52e40f2430c/packages/crypto/src/shared/keccak256.ts#L3) in the TS SDK, but this doesn’t serve my purpose (takes in a Uint8Array-like object).

“Complex” struct:

```rust
struct Key {
    one: u256,
    two: u64,
    three: bool,
}

impl Hash for Key {
    fn hash(self, ref mut state: Hasher) {
        self.one.hash(state);
        self.two.hash(state);
        self.three.hash(state);
    }
}

// hashed on-chain via:
keccak256(Key {
    one: 69,
    two: 420,
    three: true
})

```

Minimal contract reproduction:

```rust
contract;

use std::hash::*;

abi TestHash {
    fn hash_key() -> b256;
}

struct Key {
    one: u256,
    two: u64,
    three: bool,
}

impl Hash for Key {
    fn hash(self, ref mut state: Hasher) {
        self.one.hash(state);
        self.two.hash(state);
        self.three.hash(state);
    }
}

impl TestHash for Contract {
    fn hash_key() -> b256 {
        keccak256(Key {
            one: 69,
            two: 420,
            three: true
        })
    }
}

#[test]
fn test_from() {
    let contr = abi(TestHash, CONTRACT_ID);
    log(contr.hash_key());
}

```

running with `forc test --logs --decode` yield:

```bash
Decoded log value: Bits256([29, 85, 43, 160, 236, 142, 226, 39, 227, 220, 79, 104, 17, 212, 102, 24, 162, 131, 124, 238, 200, 233, 17, 235, 223, 27, 251, 89, 44, 57, 100, 246]), log rb: 8961848586872524460
Raw logs:
[{"LogData":{"data":"1d552ba0ec8ee227e3dc4f6811d46618a2837ceec8e911ebdf1bfb592c3964f6","digest":"6b06c13e935681097361fd4505c7256fc8cf4ad603a35546b875958da41fd1ff","id":"0000000000000000000000000000000000000000000000000000000000000000","is":10368,"len":32,"pc":12632,"ptr":67103622,"ra":0,"rb":8961848586872524460}}]

```

---

<div class="post-metadata">

### Author: ![theAusicist](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/theausicist/32/1987_2.png) [@theAusicist](https://forum.fuel.network/u/theAusicist)
#### Post date: [June 10, 2024, 9:44am UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/2 "2024-06-10T09:44:23Z")

</div>

cc @danielbate @IGI-111 @calldelegation

---

<div class="post-metadata">

### Author: ![danielbate](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/danielbate/32/1617_2.png) [@danielbate](https://forum.fuel.network/u/danielbate)
#### Post date: [June 11, 2024, 11:56am UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/3 "2024-06-11T11:56:10Z")

</div>

You could use the `StructCoder` directly if you know the shape of the struct. Based on your above example you could use:

```ts
import { StructCoder, BigNumberCoder, BooleanCoder, keccak256 } from 'fuels';

const structCoder = new StructCoder('Key', {
  one: new BigNumberCoder('u256'),
  two: new BigNumberCoder('u64'),
  three: new BooleanCoder,
});

const encodedStruct: UInt8Array = structCoder.encode(myStruct);
const hashedStruct = keccak256(encodedStruct);

```

Or do you need something like [EIP-712](https://eips.ethereum.org/EIPS/eip-712)?

---

<div class="post-metadata">

### Author: ![theAusicist](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/theausicist/32/1987_2.png) [@theAusicist](https://forum.fuel.network/u/theAusicist)
#### Post date: [June 11, 2024, 2:18pm UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/4 "2024-06-11T14:18:35Z")

</div>

oh super. i briefly glanced over this yesterday, but it didn’t click for me.

Trivial question, but haven’t been unable to find a solution for: `hashedStruct` is a Uint8Array of 32 elements. How can I convert that to a string? Tried `Buffer.from(hashedStruct.bufffer).toString()` but I get some weird value:

```javascript
const hashedStruct: Uint8Array= [
     29, 85, 43, 160, 236, 142, 226, 39,
    227, 220, 79, 104, 17, 212, 102, 24,
    162, 131, 124, 238, 200, 233, 17, 235,
    223, 27, 251, 89, 44, 57, 100, 246
  ]

// expected value: 0x1d552ba0ec8ee227e3dc4f6811d46618a2837ceec8e911ebdf1bfb592c3964f6

```

---

<div class="post-metadata">

### Author: ![danielbate](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/danielbate/32/1617_2.png) [@danielbate](https://forum.fuel.network/u/danielbate)
#### Post date: [June 11, 2024, 2:40pm UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/5 "2024-06-11T14:40:23Z")

</div>

Check out [hexlify](https://docs.fuel.network/docs/fuels-ts/utils/#hexlify), it’s a `utility` function for hex conversions, so call that on your encoded byte array. Conversely, we also offer `arrayify` for conversions backto `UInt8Array`.

Also potentially redundant, but if you don’t know the shape of the struct, you can also use the `AbiCoder` as long as the struct is present in the ABI (a function input/output or log type) and the coder will build out the custom struct for you.

```ts
import { AbiCoder, JsonAbiArgument, hexlify } from 'fuels';

// Picking off the my_struct input from a main function in a script ABI
const argument: JsonAbiArgument = abi.functions
  .find((f) => f.name === 'main')
  ?.inputs.find((i) => i.name === 'my_struct') as JsonAbiArgument;

const myStruct = {
  one: 1, 
  two: 2,
  three: true
};

const encoded = AbiCoder.encode(abi, argument, myStruct);
const hexed = hexlify(encoded);
// 0x123....
```

---

<div class="post-metadata">

### Author: ![theAusicist](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/theausicist/32/1987_2.png) [@theAusicist](https://forum.fuel.network/u/theAusicist)
#### Post date: [June 11, 2024, 4:09pm UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/6 "2024-06-11T16:09:02Z")

</div>

this worked. many thanks.

to boot off on your EIP-712 comment, would the process be entirely similar for encoding such structs (EIP-712 structs) for message signing?

---

<div class="post-metadata">

### Author: ![danielbate](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.fuel.network/danielbate/32/1617_2.png) [@danielbate](https://forum.fuel.network/u/danielbate)
#### Post date: [June 12, 2024, 11:53am UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/7 "2024-06-12T11:53:58Z")

</div>

So we currently don’t have a [sway standard](https://github.com/FuelLabs/sway-standards) for EIP-712 yet but I believe it’s on the roadmap, so I can’t comment specifically.

But yes I would expect it to work exactly as above and you’d append it to `signatures` on a transaction. We’d likely augment the `signMessage` functionality to accept a struct and then we do the encoding/signing rather than this being implemented by the consumer, like `signTransaction`

---

<div class="post-metadata">

### Author: ![system](https://us1.discourse-cdn.com/flex022/uploads/fuel/original/2X/5/57d5a345cc15a64b636e0d56e042857f8a0e80b1.png) [@system](https://forum.fuel.network/u/system)
#### Post date: [July 3, 2024, 7:54am UTC](https://forum.fuel.network/t/hashing-complex-structs-off-chain/5658/8 "2024-07-03T07:54:21Z")

</div>

This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.
