diff --git a/packages/atst/src/constants/defaultRpcUrl.ts b/packages/atst/src/constants/defaultRpcUrl.ts new file mode 100644 index 0000000000000000000000000000000000000000..e4c15dc4f0913a430936de709d0a3ad3b186d902 --- /dev/null +++ b/packages/atst/src/constants/defaultRpcUrl.ts @@ -0,0 +1,5 @@ +/** + * @internal + * Default RPC URL for Optimism + */ +export const DEFAULT_RPC_URL = 'https://mainnet.optimism.io' diff --git a/packages/atst/src/index.ts b/packages/atst/src/index.ts index 533c9a8bde83ed83d22792d69ba52a1565afba71..1c5b0793ac7ef12983068578340945a965c8009d 100644 --- a/packages/atst/src/index.ts +++ b/packages/atst/src/index.ts @@ -1,2 +1,15 @@ // constants export { ATTESTATION_STATION_ADDRESS } from './constants/attestationStationAddress' +// lib +export { readAttestation } from './lib/readAttestation' +export { readAttestations } from './lib/readAttestations' +export { prepareWriteAttestation } from './lib/prepareWriteAttestation' +export { prepareWriteAttestations } from './lib/prepareWriteAttestations' +export { writeAttestation } from './lib/writeAttestation' +export { abi } from './lib/abi' +export { parseAttestationBytes } from './lib/parseAttestationBytes' +export { stringifyAttestationBytes } from './lib/stringifyAttestationBytes' +// types +export type { AttestationReadParams } from './types/AttestationReadParams' +export type { WagmiBytes } from './types/WagmiBytes' +export type { DataTypeOption } from './types/DataTypeOption' diff --git a/packages/atst/src/lib/__snapshots__/logger.spec.ts.snap b/packages/atst/src/lib/__snapshots__/logger.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..7f267959435955c2afc382e36a1b11be3b052a6e --- /dev/null +++ b/packages/atst/src/lib/__snapshots__/logger.spec.ts.snap @@ -0,0 +1,11 @@ +// Vitest Snapshot v1 + +exports[`logger > \${level}() > logs message "error" 1`] = `"[31merror[39m"`; + +exports[`logger > \${level}() > logs message "info" 1`] = `"[34minfo[39m"`; + +exports[`logger > \${level}() > logs message "log" 1`] = `"[37mlog[39m"`; + +exports[`logger > \${level}() > logs message "success" 1`] = `"[32msuccess[39m"`; + +exports[`logger > \${level}() > logs message "warn" 1`] = `"[33mwarn[39m"`; diff --git a/packages/atst/src/lib/parseAttestationBytes.spec.ts b/packages/atst/src/lib/parseAttestationBytes.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..738a64b946e98709f4a532aa50c216262fc9ec66 --- /dev/null +++ b/packages/atst/src/lib/parseAttestationBytes.spec.ts @@ -0,0 +1,42 @@ +import { BigNumber } from 'ethers' +import { toUtf8Bytes } from 'ethers/lib/utils.js' +import { expect, describe, it } from 'vitest' + +import { WagmiBytes } from '../types/WagmiBytes' +import { parseAttestationBytes } from './parseAttestationBytes' + +describe(parseAttestationBytes.name, () => { + it('works for strings', () => { + const str = 'Hello World' + const bytes = BigNumber.from(toUtf8Bytes(str)).toHexString() as WagmiBytes + expect(parseAttestationBytes(bytes, 'string')).toBe(str) + }) + + it('works for numbers', () => { + const num = 123 + const bytes = BigNumber.from(num).toHexString() as WagmiBytes + expect(parseAttestationBytes(bytes, 'number')).toBe(num.toString()) + }) + + it('works for addresses', () => { + const addr = '0x1234567890123456789012345678901234567890' + const bytes = BigNumber.from(addr).toHexString() as WagmiBytes + expect(parseAttestationBytes(bytes, 'address')).toBe(addr) + }) + + it('works for booleans', () => { + const bytes = BigNumber.from(1).toHexString() as WagmiBytes + expect(parseAttestationBytes(bytes, 'bool')).toBe('true') + }) + + it('should work for raw bytes', () => { + const bytes = '0x420' + expect(parseAttestationBytes(bytes, 'bytes')).toBe(bytes) + }) + + it('should return raw bytes for invalid type', () => { + const bytes = '0x420' + // @ts-expect-error - this is a test for an error case + expect(parseAttestationBytes(bytes, 'foo')).toBe(bytes) + }) +}) diff --git a/packages/atst/src/lib/parseAttestationBytes.ts b/packages/atst/src/lib/parseAttestationBytes.ts new file mode 100644 index 0000000000000000000000000000000000000000..46de7fea14007767d7cf5478364c3737435f8646 --- /dev/null +++ b/packages/atst/src/lib/parseAttestationBytes.ts @@ -0,0 +1,28 @@ +import { BigNumber } from 'ethers' +import { toUtf8String } from 'ethers/lib/utils.js' + +import type { DataTypeOption } from '../types/DataTypeOption' +import type { WagmiBytes } from '../types/WagmiBytes' + +export const parseAttestationBytes = ( + attestationBytes: WagmiBytes, + dataType: DataTypeOption +) => { + if (dataType === 'bytes') { + return attestationBytes + } + if (dataType === 'number') { + return BigNumber.from(attestationBytes).toString() + } + if (dataType === 'address') { + return BigNumber.from(attestationBytes).toHexString() + } + if (dataType === 'bool') { + return BigNumber.from(attestationBytes).gt(0) ? 'true' : 'false' + } + if (dataType === 'string') { + return attestationBytes && toUtf8String(attestationBytes) + } + console.warn(`unrecognized dataType ${dataType satisfies never}`) + return attestationBytes +} diff --git a/packages/atst/src/lib/prepareWriteAttestation.spec.ts b/packages/atst/src/lib/prepareWriteAttestation.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..750348fd6c852da1851a351ff647c24a636803b1 --- /dev/null +++ b/packages/atst/src/lib/prepareWriteAttestation.spec.ts @@ -0,0 +1,71 @@ +import { connect, createClient } from '@wagmi/core' +import { providers, Wallet } from 'ethers' +import { expect, describe, it, beforeAll } from 'vitest' +import { MockConnector } from '@wagmi/core/connectors/mock' + +import { prepareWriteAttestation } from './prepareWriteAttestation' +import { readAttestation } from './readAttestation' + +const creator = '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3' +const about = '0x2335022c740d17c2837f9C884Bfe4fFdbf0A95D5' +const key = 'optimist.base-uri' + +const chainId = 10 + +const provider = new providers.JsonRpcProvider( + { + url: 'http://localhost:8545', + }, + chainId +) + +const wallet = Wallet.createRandom({ provider }) + +createClient({ + provider, +}) + +beforeAll(async () => { + await connect({ + connector: new MockConnector({ + options: { + chainId, + signer: new Wallet(wallet.privateKey, provider), + }, + }), + }) +}) + +describe(prepareWriteAttestation.name, () => { + it('Should correctly prepare an attestation', async () => { + const result = await prepareWriteAttestation(about, key, 'hello world') + + expect(result.address).toMatchInlineSnapshot( + '"0xEE36eaaD94d1Cc1d0eccaDb55C38bFfB6Be06C77"' + ) + expect(result.chainId).toMatchInlineSnapshot('10') + expect(result.functionName).toMatchInlineSnapshot('"attest"') + expect(result.mode).toMatchInlineSnapshot('"prepared"') + expect(result.request.gasLimit).toMatchInlineSnapshot(` + { + "hex": "0xd6c9", + "type": "BigNumber", + } + `) + }) + + it('should throw an error if key is longer than 32 bytes', async () => { + const dataType = 'string' + + await expect( + readAttestation( + creator, + about, + 'this is a key that is way longer than 32 bytes so this key should throw an error matching the inline snapshot', + dataType + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"Key is longer than the max length of 32 for attestation keys"' + ) + }) +}) diff --git a/packages/atst/src/lib/prepareWriteAttestation.ts b/packages/atst/src/lib/prepareWriteAttestation.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3e9eebbdda12fc26d9b3b826b1038f24f823076 --- /dev/null +++ b/packages/atst/src/lib/prepareWriteAttestation.ts @@ -0,0 +1,24 @@ +import { Address, prepareWriteContract } from '@wagmi/core' +import { formatBytes32String } from 'ethers/lib/utils.js' + +import { ATTESTATION_STATION_ADDRESS } from '../constants/attestationStationAddress' +import { WagmiBytes } from '../types/WagmiBytes' +import { abi } from './abi' +import { stringifyAttestationBytes } from './stringifyAttestationBytes' + +export const prepareWriteAttestation = async ( + about: Address, + key: string, + value: string | WagmiBytes | number | boolean, + chainId = 10, + contractAddress: Address = ATTESTATION_STATION_ADDRESS +) => { + const formattedKey = formatBytes32String(key) as WagmiBytes + return prepareWriteContract({ + address: contractAddress, + abi, + functionName: 'attest', + chainId, + args: [about, formattedKey, stringifyAttestationBytes(value) as WagmiBytes], + }) +} diff --git a/packages/atst/src/lib/prepareWriteAttestations.spec.ts b/packages/atst/src/lib/prepareWriteAttestations.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..bb49dbe21373eb704a54aa2c0055be9084be5304 --- /dev/null +++ b/packages/atst/src/lib/prepareWriteAttestations.spec.ts @@ -0,0 +1,77 @@ +import { connect, createClient } from '@wagmi/core' +import { providers, Wallet } from 'ethers' +import { expect, describe, it, beforeAll } from 'vitest' +import { MockConnector } from '@wagmi/core/connectors/mock' + +import { readAttestation } from './readAttestation' +import { prepareWriteAttestations } from './prepareWriteAttestations' + +const creator = '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3' +const about = '0x2335022c740d17c2837f9C884Bfe4fFdbf0A95D5' +const key = 'optimist.base-uri' + +const chainId = 10 + +const provider = new providers.JsonRpcProvider( + { + url: 'http://localhost:8545', + }, + chainId +) + +const wallet = Wallet.createRandom({ provider }) + +createClient({ + provider, +}) + +beforeAll(async () => { + await connect({ + connector: new MockConnector({ + options: { + chainId, + signer: new Wallet(wallet.privateKey, provider), + }, + }), + }) +}) + +describe(prepareWriteAttestations.name, () => { + it('Should correctly prepare an attestation', async () => { + const result = await prepareWriteAttestations([ + { + about, + key, + value: 'hello world', + }, + ]) + + expect(result.address).toMatchInlineSnapshot( + '"0xEE36eaaD94d1Cc1d0eccaDb55C38bFfB6Be06C77"' + ) + expect(result.chainId).toMatchInlineSnapshot('10') + expect(result.functionName).toMatchInlineSnapshot('"attest"') + expect(result.mode).toMatchInlineSnapshot('"prepared"') + expect(result.request.gasLimit).toMatchInlineSnapshot(` + { + "hex": "0xd9ce", + "type": "BigNumber", + } + `) + }) + + it('should throw an error if key is longer than 32 bytes', async () => { + const dataType = 'string' + + await expect( + readAttestation( + creator, + about, + 'this is a key that is way longer than 32 bytes so this key should throw an error matching the inline snapshot', + dataType + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"Key is longer than the max length of 32 for attestation keys"' + ) + }) +}) diff --git a/packages/atst/src/lib/prepareWriteAttestations.ts b/packages/atst/src/lib/prepareWriteAttestations.ts new file mode 100644 index 0000000000000000000000000000000000000000..da2162597ed1d4faa89224315a9bbfdcf0a13cd5 --- /dev/null +++ b/packages/atst/src/lib/prepareWriteAttestations.ts @@ -0,0 +1,38 @@ +import { Address, prepareWriteContract } from '@wagmi/core' +import { formatBytes32String } from 'ethers/lib/utils.js' + +import { ATTESTATION_STATION_ADDRESS } from '../constants/attestationStationAddress' +import { WagmiBytes } from '../types/WagmiBytes' +import { abi } from './abi' +import { stringifyAttestationBytes } from './stringifyAttestationBytes' + +type Attestation = { + about: Address + key: string + value: string | WagmiBytes | number | boolean +} + +export const prepareWriteAttestations = async ( + attestations: Attestation[], + chainId = 10, + contractAddress: Address = ATTESTATION_STATION_ADDRESS +) => { + const formattedAttestations = attestations.map((attestation) => { + const formattedKey = formatBytes32String(attestation.key) as WagmiBytes + const formattedValue = stringifyAttestationBytes( + attestation.value + ) as WagmiBytes + return { + about: attestation.about, + key: formattedKey, + val: formattedValue, + } as const + }) + return prepareWriteContract({ + address: contractAddress, + abi, + functionName: 'attest', + chainId, + args: [formattedAttestations], + }) +} diff --git a/packages/atst/src/lib/readAttestation.spec.ts b/packages/atst/src/lib/readAttestation.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..5df88a8852163999ffab44bb5287f9eb0fc559f6 --- /dev/null +++ b/packages/atst/src/lib/readAttestation.spec.ts @@ -0,0 +1,41 @@ +import { createClient } from '@wagmi/core' +import { providers } from 'ethers' +import { expect, describe, it } from 'vitest' + +import { readAttestation } from './readAttestation' + +const creator = '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3' +const about = '0x2335022c740d17c2837f9C884Bfe4fFdbf0A95D5' +const key = 'optimist.base-uri' +const dataType = 'string' + +const provider = new providers.JsonRpcProvider({ + url: 'http://localhost:8545', +}) + +createClient({ + provider, +}) + +describe(readAttestation.name, () => { + it('should return the attestation from attestation station', async () => { + const result = await readAttestation(creator, about, key, dataType) + + expect(result).toMatchInlineSnapshot( + '"https://assets.optimism.io/4a609661-6774-441f-9fdb-453fdbb89931-bucket/optimist-nft/attributes"' + ) + }) + + it('should throw an error if key is longer than 32 bytes', async () => { + await expect( + readAttestation( + creator, + about, + 'this is a key that is way longer than 32 bytes so this key should throw an error matching the inline snapshot', + dataType + ) + ).rejects.toThrowErrorMatchingInlineSnapshot( + '"Key is longer than the max length of 32 for attestation keys"' + ) + }) +}) diff --git a/packages/atst/src/lib/readAttestation.ts b/packages/atst/src/lib/readAttestation.ts new file mode 100644 index 0000000000000000000000000000000000000000..ccaa057dab8f3491b64d466be14cb6d866f4b0cc --- /dev/null +++ b/packages/atst/src/lib/readAttestation.ts @@ -0,0 +1,35 @@ +import type { Address } from '@wagmi/core' + +import { DataTypeOption, DEFAULT_DATA_TYPE } from '../types/DataTypeOption' +import { readAttestations } from './readAttestations' + +/** + * reads attestation from the attestation station contract + * + * @param attestationRead - the parameters for reading an attestation + * @returns attestation result + * @throws Error if key is longer than 32 bytes + * @example + * const attestation = await readAttestation( + * { + * creator: creatorAddress, + * about: aboutAddress, + * key: 'my_key', + * }, + */ +export const readAttestation = async ( + creator: Address, + about: Address, + key: string, + dataType: DataTypeOption = DEFAULT_DATA_TYPE, + contractAddress: Address = '0xEE36eaaD94d1Cc1d0eccaDb55C38bFfB6Be06C77' +) => { + const [result] = await readAttestations({ + creator, + about, + key, + dataType, + contractAddress, + }) + return result +} diff --git a/packages/atst/src/lib/readAttestations.spec.ts b/packages/atst/src/lib/readAttestations.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6fd5ba2f5805ff397862bb6c1de6836b824f4e33 --- /dev/null +++ b/packages/atst/src/lib/readAttestations.spec.ts @@ -0,0 +1,62 @@ +import { createClient } from '@wagmi/core' +import { providers } from 'ethers' +import { expect, describe, it } from 'vitest' + +import { readAttestation } from './readAttestation' +import { readAttestations } from './readAttestations' + +const creator = '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3' +const about = '0x2335022c740d17c2837f9C884Bfe4fFdbf0A95D5' +const key = 'optimist.base-uri' + +const provider = new providers.JsonRpcProvider({ + url: 'http://localhost:8545', +}) + +createClient({ + provider, +}) + +describe(readAttestation.name, () => { + it('should return attestations from attestation station', async () => { + const dataType = 'string' + + const result = await readAttestations( + { + creator, + about, + key, + dataType, + }, + { + creator, + about, + key, + dataType: 'bool', + }, + { + creator, + about, + key, + dataType: 'bytes', + }, + { + creator, + about, + key, + dataType: 'number', + } + ) + + expect(result).toMatchInlineSnapshot( + ` + [ + "https://assets.optimism.io/4a609661-6774-441f-9fdb-453fdbb89931-bucket/optimist-nft/attributes", + "true", + "0x68747470733a2f2f6173736574732e6f7074696d69736d2e696f2f34613630393636312d363737342d343431662d396664622d3435336664626238393933312d6275636b65742f6f7074696d6973742d6e66742f61747472696275746573", + "9665973469795080068873111198635018086067645613429821071805084917303478255842407465257371959707311987533859075426222329066766033171696373249109388415320911537042272090516917683029511016473045453921068327933733922308146003731827", + ] + ` + ) + }) +}) diff --git a/packages/atst/src/lib/readAttestations.ts b/packages/atst/src/lib/readAttestations.ts new file mode 100644 index 0000000000000000000000000000000000000000..af1cca23fea4cec17c3b7acdc7e3957ea6f518e4 --- /dev/null +++ b/packages/atst/src/lib/readAttestations.ts @@ -0,0 +1,67 @@ +import { readContracts } from '@wagmi/core' +import { formatBytes32String } from 'ethers/lib/utils.js' + +import { ATTESTATION_STATION_ADDRESS } from '../constants/attestationStationAddress' +import type { AttestationReadParams } from '../types/AttestationReadParams' +import { DEFAULT_DATA_TYPE } from '../types/DataTypeOption' +import type { WagmiBytes } from '../types/WagmiBytes' +import { abi } from './abi' +import { parseAttestationBytes } from './parseAttestationBytes' + +/** + * reads attestations from the attestation station contract + * + * @returns an array of attestation values + * @throws Error if key is longer than 32 bytes + * @example + * const attestations = await readAttestations( + * { + * creator: creatorAddress, + * about: aboutAddress, + * key: 'my_key', + * allowFailure: false, + * }, + * { + * creator: creatorAddress2, + * about: aboutAddress2, + * key: 'my_key', + * dataType: 'number', + * contractAddress: '0x1234', + * allowFailure: false, + * }, + * ) + */ +export const readAttestations = async ( + ...attestationReads: Array<AttestationReadParams> +) => { + const calls = attestationReads.map((attestation) => { + const { + creator, + about, + key, + contractAddress = ATTESTATION_STATION_ADDRESS, + allowFailure = false, + } = attestation + if (key.length > 32) { + throw new Error( + 'Key is longer than the max length of 32 for attestation keys' + ) + } + return { + address: contractAddress, + abi, + functionName: 'attestations', + args: [creator, about, formatBytes32String(key) as WagmiBytes], + allowFailure, + } as const + }) + + const results = await readContracts({ + contracts: calls, + }) + + return results.map((dataBytes, i) => { + const dataType = attestationReads[i].dataType ?? DEFAULT_DATA_TYPE + return parseAttestationBytes(dataBytes, dataType) + }) +} diff --git a/packages/atst/src/lib/stringifyAttestationBytes.ts b/packages/atst/src/lib/stringifyAttestationBytes.ts new file mode 100644 index 0000000000000000000000000000000000000000..424958d76aa444681a312be8088683a64298920e --- /dev/null +++ b/packages/atst/src/lib/stringifyAttestationBytes.ts @@ -0,0 +1,26 @@ +import { Address } from '@wagmi/core' +import { BigNumber } from 'ethers' +import { isAddress, isHexString, toUtf8Bytes } from 'ethers/lib/utils.js' + +import { WagmiBytes } from '../types/WagmiBytes' + +export const stringifyAttestationBytes = ( + bytes: WagmiBytes | string | Address | number | boolean +) => { + if (typeof bytes === 'number') { + return BigNumber.from(bytes).toHexString() + } + if (typeof bytes === 'boolean') { + return bytes ? '0x1' : '0x0' + } + if (isAddress(bytes)) { + return bytes + } + if (isHexString(bytes)) { + return bytes + } + if (typeof bytes === 'string') { + return toUtf8Bytes(bytes) + } + throw new Error(`unrecognized bytes type ${bytes satisfies never}`) +} diff --git a/packages/atst/src/lib/writeAttestation.spec.ts b/packages/atst/src/lib/writeAttestation.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..46bd7d3637125ba223bcc212441b160a3b0c7871 --- /dev/null +++ b/packages/atst/src/lib/writeAttestation.spec.ts @@ -0,0 +1,10 @@ +import { writeContract } from '@wagmi/core' +import { describe, expect, it } from 'vitest' + +import { writeAttestation } from './writeAttestation' + +describe(writeAttestation.name, () => { + it('rexports writeContract from @wagmi/core', () => { + expect(writeAttestation).toBe(writeContract) + }) +}) diff --git a/packages/atst/src/lib/writeAttestation.ts b/packages/atst/src/lib/writeAttestation.ts new file mode 100644 index 0000000000000000000000000000000000000000..14db0d35d6c376ca8d1aeaa5329f6c9d2f6b1e5a --- /dev/null +++ b/packages/atst/src/lib/writeAttestation.ts @@ -0,0 +1,15 @@ +import { writeContract } from '@wagmi/core' +export { prepareWriteAttestation } from './prepareWriteAttestation' + +export { abi } from './abi' + +/** + * Writes an attestation to the blockchain + * Same function as `writeContract` from @wagmi/core + * To use first use prepareWriteContract + * + * @example + * const config = await prepareAttestation(about, key, value) + * const tx = await writeAttestation(config) + */ +export const writeAttestation = writeContract diff --git a/packages/atst/src/types/AttestationReadParams.ts b/packages/atst/src/types/AttestationReadParams.ts new file mode 100644 index 0000000000000000000000000000000000000000..71bb6c12baad54da9a51fdddaf5b3443025a1430 --- /dev/null +++ b/packages/atst/src/types/AttestationReadParams.ts @@ -0,0 +1,15 @@ +import { Address } from '@wagmi/core' + +import { DataTypeOption } from './DataTypeOption' + +/** + * The parameters for reading bulk attestations + */ +export interface AttestationReadParams { + creator: Address + about: Address + key: string + dataType?: DataTypeOption + contractAddress?: Address + allowFailure?: boolean +} diff --git a/packages/atst/src/types/DataTypeOption.ts b/packages/atst/src/types/DataTypeOption.ts new file mode 100644 index 0000000000000000000000000000000000000000..7159fc77b9d0c70787d39b522652fc02ff4dd07c --- /dev/null +++ b/packages/atst/src/types/DataTypeOption.ts @@ -0,0 +1,28 @@ +import { z } from 'zod' + +/** + * @internal + * Default data type for attestations + */ +export const DEFAULT_DATA_TYPE = 'string' as const + +/** + * Zod validator for the DataType type + * string | bytes | number | bool | address + */ +export const dataTypeOptionValidator = z + .union([ + z.literal('string'), + z.literal('bytes'), + z.literal('number'), + z.literal('bool'), + z.literal('address'), + ]) + .optional() + .default('string').describe(`Zod validator for the DataType type + string | bytes | number | bool | address`) + +/** + * Options for attestation data type + */ +export type DataTypeOption = z.infer<typeof dataTypeOptionValidator> diff --git a/packages/atst/src/types/WagmiBytes.ts b/packages/atst/src/types/WagmiBytes.ts new file mode 100644 index 0000000000000000000000000000000000000000..c4d127df57557b90f04e19f8ba926b72f05baf2f --- /dev/null +++ b/packages/atst/src/types/WagmiBytes.ts @@ -0,0 +1,5 @@ +/** + * @internal + * WagmiBytes is a type that represents a hex string with a length of 32 bytes. + */ +export type WagmiBytes = `0x${string}` diff --git a/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol b/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol index dcf3521414906c931792103a18fd964f6598085a..6a13d7d1033e9eddf99c288ef24360d77c34cc83 100644 --- a/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol +++ b/packages/contracts-bedrock/contracts/L1/ResourceMetering.sol @@ -96,11 +96,11 @@ abstract contract ResourceMetering is Initializable { // Update base fee by adding the base fee delta and clamp the resulting value between // min and max. - int256 newBaseFee = Arithmetic.clamp( - int256(uint256(params.prevBaseFee)) + baseFeeDelta, - MINIMUM_BASE_FEE, - MAXIMUM_BASE_FEE - ); + int256 newBaseFee = Arithmetic.clamp({ + _value: int256(uint256(params.prevBaseFee)) + baseFeeDelta, + _min: MINIMUM_BASE_FEE, + _max: MAXIMUM_BASE_FEE + }); // If we skipped more than one block, we also need to account for every empty block. // Empty block means there was no demand for deposits in that block, so we should @@ -109,15 +109,15 @@ abstract contract ResourceMetering is Initializable { // Update the base fee by repeatedly applying the exponent 1-(1/change_denominator) // blockDiff - 1 times. Simulates multiple empty blocks. Clamp the resulting value // between min and max. - newBaseFee = Arithmetic.clamp( - Arithmetic.cdexp( - newBaseFee, - BASE_FEE_MAX_CHANGE_DENOMINATOR, - int256(blockDiff - 1) - ), - MINIMUM_BASE_FEE, - MAXIMUM_BASE_FEE - ); + newBaseFee = Arithmetic.clamp({ + _value: Arithmetic.cdexp({ + _coefficient: newBaseFee, + _denominator: BASE_FEE_MAX_CHANGE_DENOMINATOR, + _exponent: int256(blockDiff - 1) + }), + _min: MINIMUM_BASE_FEE, + _max: MAXIMUM_BASE_FEE + }); } // Update new base fee, reset bought gas, and update block number. @@ -141,7 +141,7 @@ abstract contract ResourceMetering is Initializable { // division by zero for L1s that don't support 1559 or to avoid excessive gas burns during // periods of extremely low L1 demand. One-day average gas fee hasn't dipped below 1 gwei // during any 1 day period in the last 5 years, so should be fine. - uint256 gasCost = resourceCost / Math.max(block.basefee, 1000000000); + uint256 gasCost = resourceCost / Math.max(block.basefee, 1 gwei); // Give the user a refund based on the amount of gas they used to do all of the work up to // this point. Since we're at the end of the modifier, this should be pretty accurate. Acts diff --git a/packages/contracts-periphery/contracts/universal/op-nft/AttestationStation.sol b/packages/contracts-periphery/contracts/universal/op-nft/AttestationStation.sol index c6c3d083bdde080239402b4135d8fbfbb1962c6e..762612f74d87d11f4beda973293542e3836da401 100644 --- a/packages/contracts-periphery/contracts/universal/op-nft/AttestationStation.sol +++ b/packages/contracts-periphery/contracts/universal/op-nft/AttestationStation.sol @@ -68,7 +68,7 @@ contract AttestationStation is Semver { /** * @notice Allows anyone to create attestations. * - * @param _attestations An array of attestation data. + * @param _attestations An array of AttestationData structs. */ function attest(AttestationData[] calldata _attestations) external { uint256 length = _attestations.length;