cowprotocol / solver-rewards

Data Aggregation for Solver Reimbursement & Rewards Distributor
Other
8 stars 5 forks source link

Use Fixed Type for EVM Addresses #236

Open bh2smith opened 1 year ago

bh2smith commented 1 year ago

Some of our code is a bit brittle because of the loosely thrown around primitive strings. Some libraries use checksum addresses and others use lowercase. We should make this uniform across the project so to avoid these ugly little fixes.

This change is a bit ugly and is a result of having to "normalize" hex strings. We should probably find a global/universal solution to this problem instead of having to make conversions all the time.

_Originally posted by @bh2smith in https://github.com/cowprotocol/solver-rewards/pull/231#discussion_r1163365987_

bh2smith commented 1 year ago

An approach proposed by @tukantje on slack is as follows:

type Nominal<T extends string, K> = {
  _type: T
  value: K
}

type Address = Nominal<"Address", string>

const addressRegex = new RegExp("^0x[a-fA-F0-9]{40}$/")

function isAddressString(value: string) {
  return addressRegex.test(value)
}

function isAddress(nominal: Nominal<string, any>): nominal is Address {
  return isAddressString(nominal.value)
}

function makeAddress(text: string): Address {
  if (!isAddressString(text)) {
    // Could also return null, depends on your usecase.
    throw new Error(`Invalid text supplied: can't make an address out of ${text}`)
  }

  return Object.freeze({
    value: text,
    _type: "Address"
  })
}

const address = makeAddress("0x23233222"); // Expected to fail, not a valid address.
bh2smith commented 1 year ago

Apparently also, this is "coming soon"

https://github.com/microsoft/TypeScript/issues/41160

There is this cheeky trick (that isn't super useful).

type Address = `0x${Lowercase<string>}`

and ethers offers this method: https://docs.ethers.org/v6/api/address/#getAddress