Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/fine-nights-lay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@mimicprotocol/cli": patch
"@mimicprotocol/lib-ts": patch
"@mimicprotocol/test-ts": patch
---

Fix clashing Result import
21 changes: 15 additions & 6 deletions packages/cli/src/lib/AbisInterfaceGenerator/FunctionHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ export default class FunctionHandler {
const capitalizedName = this.getCapitalizedName(fn)

const isPayable = fn.stateMutability === 'payable'
const hasValueParameter = inputs.some((input) => input.escapedName === 'value')
const payableParamName = isPayable && hasValueParameter ? '_payableValue' : 'value'
const fullMethodParams = methodParams.concat(
isPayable ? `${methodParams.length > 0 ? ', ' : ''}value: ${LibTypes.BigInt}` : ''
isPayable
? `${methodParams.length > 0 ? ', ' : ''}${payableParamName}: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()`
: ''
)

lines.push(`${methodName}(${fullMethodParams}): ${returnType} {`)
Expand All @@ -100,7 +104,7 @@ export default class FunctionHandler {
if (isPayable) importManager.addType(LibTypes.BigInt)

lines.push(
`return EvmCallBuilder.forChain(this._chainId).addCall(this._address, encodedData${isPayable ? ', value' : ''})`
`return EvmCallBuilder.forChain(this._chainId).addCall(this._address, encodedData${isPayable ? `, ${payableParamName}` : ''})`
)

lines.push(`}`)
Expand All @@ -127,7 +131,10 @@ export default class FunctionHandler {
const isVoid = returnType === 'void'
if (isVoid) importManager.addType(LibTypes.Void)

const resultReturnType = isVoid ? `Result<${LibTypes.Void}, string>` : `Result<${returnType}, string>`
const resultIdentifier = NameManager.getImportNameForCode('Result')
const resultReturnType = isVoid
? `${resultIdentifier}<${LibTypes.Void}, string>`
: `${resultIdentifier}<${returnType}, string>`
lines.push(`${methodName}(${methodParams}): ${resultReturnType} {`)

lines.push(
Expand All @@ -138,14 +145,16 @@ export default class FunctionHandler {

lines.push(`const response = ${contractCallLine}`)
lines.push(
`if (response.isError) return Result.err<${isVoid ? LibTypes.Void : returnType}, string>(response.error)`
`if (response.isError) return ${resultIdentifier}.err<${
isVoid ? LibTypes.Void : returnType
}, string>(response.error)`
)

if (isVoid) {
lines.push(`return Result.ok<${LibTypes.Void}, string>(new ${LibTypes.Void}())`)
lines.push(`return ${resultIdentifier}.ok<${LibTypes.Void}, string>(new ${LibTypes.Void}())`)
} else {
lines.push(`const decoded = ${contractName}Utils.decode${capitalizedName}(response.unwrap())`)
lines.push(`return Result.ok<${returnType}, string>(decoded)`)
lines.push(`return ${resultIdentifier}.ok<${returnType}, string>(decoded)`)
}

lines.push(`}`)
Expand Down
5 changes: 4 additions & 1 deletion packages/cli/src/lib/AbisInterfaceGenerator/ImportManager.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import NameManager from './NameManager'
import { ImportedTypes } from './types'

export default class ImportManager {
Expand All @@ -15,6 +16,8 @@ export default class ImportManager {
if (this.types.size === 0) return ''

const sortedTypes = [...this.types].sort((a, b) => String(a).localeCompare(String(b)))
return `import { ${sortedTypes.join(', ')} } from '@mimicprotocol/lib-ts'`
const importIdentifiers = sortedTypes.map((type) => NameManager.formatImportStatement(type))

return `import { ${importIdentifiers.join(', ')} } from '@mimicprotocol/lib-ts'`
}
}
22 changes: 18 additions & 4 deletions packages/cli/src/lib/AbisInterfaceGenerator/NameManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,13 @@ export enum NameContext {
LOCAL_VARIABLE = 'local_variable',
CLASS_PROPERTY = 'class_property',
METHOD_NAME = 'method_name',
TUPLE_CLASS_NAME = 'tuple_class_name',
}

export default class NameManager {
private static readonly IMPORT_ALIASES: Partial<Record<LibTypes, string>> = {
Result: '_Result',
}

private static readonly RESERVED_BY_CONTEXT: Record<NameContext, Set<string>> = {
[NameContext.FUNCTION_PARAMETER]: new Set([
'response',
Expand All @@ -33,7 +36,6 @@ export default class NameManager {
'timestamp',
]),
[NameContext.METHOD_NAME]: new Set(['constructor']),
[NameContext.TUPLE_CLASS_NAME]: new Set([...Object.values(LibTypes), 'JSON']),
}

private static readonly INTERNAL_NAME_PATTERNS = [/^item\d+$/, /^s\d+$/]
Expand Down Expand Up @@ -81,6 +83,20 @@ export default class NameManager {
}))
}

public static getImportNameForCode(type: string): string {
const alias = this.getImportAlias(type)
return alias ?? type
}

public static formatImportStatement(type: string): string {
const alias = this.getImportAlias(type)
return alias ? `${type} as ${alias}` : type
}

private static getImportAlias(type: string): string | null {
return this.IMPORT_ALIASES[type as LibTypes] ?? null
}

private static hasConflict(name: string, context: NameContext): boolean {
if (this.RESERVED_BY_CONTEXT[context]?.has(name)) return true

Expand Down Expand Up @@ -112,8 +128,6 @@ export default class NameManager {
return '_prop'
case NameContext.METHOD_NAME:
return '_'
case NameContext.TUPLE_CLASS_NAME:
return '_class'
default:
return '_safe'
}
Expand Down
2 changes: 0 additions & 2 deletions packages/cli/src/lib/AbisInterfaceGenerator/TupleHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ export default class TupleHandler {
if (structMatch && structMatch[1]) className = structMatch[1]
}

className = NameManager.escapeName(className, NameContext.TUPLE_CLASS_NAME)

const key = baseInternalType || className
const components = this.resolveComponentNames(tupleToDefine.components, NameContext.CLASS_PROPERTY)

Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ export enum LibTypes {
Address = 'Address',
Bytes = 'Bytes',
ChainId = 'ChainId',
TokenAmount = 'TokenAmount',
Void = 'Void',
Result = 'Result',
JSON = 'JSON',
}

export enum AssemblyPrimitiveTypes {
Expand Down
56 changes: 31 additions & 25 deletions packages/cli/tests/AbisInterfaceGenerator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,10 @@ describe('AbisInterfaceGenerator', () => {

const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain(`getData(): Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`getData(): _Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`getData_1(id: ${LibTypes.BigInt}): EvmCallBuilder {`)
expect(result).to.contain(
`getData_2(id: ${LibTypes.BigInt}, flag: ${AssemblyPrimitiveTypes.bool}, value: ${LibTypes.BigInt}): EvmCallBuilder {`
`getData_2(id: ${LibTypes.BigInt}, flag: ${AssemblyPrimitiveTypes.bool}, value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`
)
})

Expand All @@ -120,12 +120,12 @@ describe('AbisInterfaceGenerator', () => {

const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain(`getBalance(): Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`getBalance(): _Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`transfer(to: ${LibTypes.Address}): EvmCallBuilder {`)
expect(result).to.contain(`getBalance_1(owner: ${LibTypes.Address}): Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`getName(): Result<${AssemblyPrimitiveTypes.string}, string> {`)
expect(result).to.contain(`getBalance_1(owner: ${LibTypes.Address}): _Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`getName(): _Result<${AssemblyPrimitiveTypes.string}, string> {`)
expect(result).to.contain(
`transfer_1(to: ${LibTypes.Address}, amount: ${LibTypes.BigInt}, value: ${LibTypes.BigInt}): EvmCallBuilder {`
`transfer_1(to: ${LibTypes.Address}, amount: ${LibTypes.BigInt}, value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`
)
})

Expand All @@ -137,7 +137,7 @@ describe('AbisInterfaceGenerator', () => {

const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain(`constructor_(): Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`constructor_(): _Result<${LibTypes.BigInt}, string> {`)
expect(result).to.contain(`constructor_1(value: ${LibTypes.BigInt}): EvmCallBuilder {`)
})
})
Expand Down Expand Up @@ -239,9 +239,9 @@ describe('AbisInterfaceGenerator', () => {
expect(result).to.contain(
`const response = environment.evmCallQuery(this._address, this._chainId, encodedData.toHexString(), this._timestamp)`
)
expect(result).to.contain(`if (response.isError) return Result.err<${LibTypes.BigInt}, string>(response.error)`)
expect(result).to.contain(`if (response.isError) return _Result.err<${LibTypes.BigInt}, string>(response.error)`)
expect(result).to.contain(`const decoded = ${CONTRACT_NAME}Utils.decodeGetBalance(response.unwrap())`)
expect(result).to.contain(`return Result.ok<${LibTypes.BigInt}, string>(decoded)`)
expect(result).to.contain(`return _Result.ok<${LibTypes.BigInt}, string>(decoded)`)
expect(result).to.contain(`export class ${CONTRACT_NAME}Utils {`)
expect(result).to.contain(`static encodeGetBalance(owner: Address): Bytes {`)
expect(result).to.contain(`static decodeGetBalance(encodedResponse: string): BigInt {`)
Expand Down Expand Up @@ -313,14 +313,14 @@ describe('AbisInterfaceGenerator', () => {

const selector = getFunctionSelector(abi[0])

expect(result).to.contain(`${functionName}(): Result<Void, string> {`)
expect(result).to.contain(`${functionName}(): _Result<Void, string> {`)
expect(result).to.contain(`static encodeNoReturn(): Bytes {`)
expect(result).to.contain(`return ${LibTypes.Bytes}.fromHexString('${selector}')`)
expect(result).to.contain(
`environment.evmCallQuery(this._address, this._chainId, encodedData.toHexString(), this._timestamp)`
)
expect(result).to.contain(`if (response.isError) return Result.err<Void, string>(response.error)`)
expect(result).to.contain(`return Result.ok<Void, string>(new Void())`)
expect(result).to.contain(`if (response.isError) return _Result.err<Void, string>(response.error)`)
expect(result).to.contain(`return _Result.ok<Void, string>(new Void())`)
expect(result).not.to.contain(`_decodeNoReturnResponse`)
})
})
Expand All @@ -336,7 +336,7 @@ describe('AbisInterfaceGenerator', () => {
]

const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)
const importMatch = result.match(/import \{ ([A-Za-z, ]+) \} from '@mimicprotocol\/lib-ts'/)?.toString()
const importMatch = result.match(/import \{ ([^}]+) \} from '@mimicprotocol\/lib-ts'/)?.toString()

expect(importMatch).not.to.be.undefined
expect(importMatch).to.contain(`${LibTypes.Address}`)
Expand All @@ -345,7 +345,7 @@ describe('AbisInterfaceGenerator', () => {
expect(importMatch).to.contain('EvmDecodeParam')
expect(importMatch).to.contain('evm')
expect(importMatch).to.contain('environment')
expect(importMatch).to.contain('Result')
expect(importMatch).to.contain('Result as _Result')
})
})

Expand Down Expand Up @@ -573,7 +573,7 @@ describe('AbisInterfaceGenerator', () => {
const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain(`transfer(to: ${LibTypes.Address}, amount: ${LibTypes.BigInt}): EvmCallBuilder {`)
expect(result).to.contain(`deposit(value: ${LibTypes.BigInt}): EvmCallBuilder {`)
expect(result).to.contain(`deposit(value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`)
})

it('should generate proper encoded data method for write functions', () => {
Expand Down Expand Up @@ -613,7 +613,7 @@ describe('AbisInterfaceGenerator', () => {
const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)
const selector = getFunctionSelector(abi[0])

expect(result).to.contain(`deposit(value: ${LibTypes.BigInt}): EvmCallBuilder {`)
expect(result).to.contain(`deposit(value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`)
expect(result).to.contain('static encodeDeposit(): Bytes {')
expect(result).to.contain(`return ${LibTypes.Bytes}.fromHexString('${selector}')`)
expect(result).to.contain(`const encodedData = ${CONTRACT_NAME}Utils.encodeDeposit()`)
Expand All @@ -629,7 +629,9 @@ describe('AbisInterfaceGenerator', () => {
const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain(`transfer(to: ${LibTypes.Address}): EvmCallBuilder {`)
expect(result).to.contain(`deposit(amount: ${LibTypes.BigInt}, value: ${LibTypes.BigInt}): EvmCallBuilder {`)
expect(result).to.contain(
`deposit(amount: ${LibTypes.BigInt}, value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`
)
})

it('should apply correct parameter conversions for write functions in encoded data method', () => {
Expand Down Expand Up @@ -685,7 +687,7 @@ describe('AbisInterfaceGenerator', () => {
`batchTransfer(recipients: ${LibTypes.Address}[], amounts: ${LibTypes.BigInt}[], flags: ${AssemblyPrimitiveTypes.bool}[]): EvmCallBuilder {`
)
expect(result).to.contain(
`depositMultiple(tokens: ${LibTypes.Address}[], values: ${LibTypes.BigInt}[], value: ${LibTypes.BigInt}): EvmCallBuilder {`
`depositMultiple(tokens: ${LibTypes.Address}[], values: ${LibTypes.BigInt}[], value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`
)

expect(result).to.contain(
Expand Down Expand Up @@ -729,7 +731,9 @@ describe('AbisInterfaceGenerator', () => {
const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain('createUser(userData: UserInfo): EvmCallBuilder {')
expect(result).to.contain(`updateProfile(profile: Tuple1, value: ${LibTypes.BigInt}): EvmCallBuilder {`)
expect(result).to.contain(
`updateProfile(profile: Tuple1, value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`
)

expect(result).to.contain(`EvmEncodeParam.fromValues('()', userData.toEvmEncodeParams())`)
expect(result).to.contain(`EvmEncodeParam.fromValues('()', profile.toEvmEncodeParams())`)
Expand Down Expand Up @@ -775,7 +779,9 @@ describe('AbisInterfaceGenerator', () => {
const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain('processOrders(orders: Tuple0[]): EvmCallBuilder {')
expect(result).to.contain(`complexOperation(data: Tuple1, value: ${LibTypes.BigInt}): EvmCallBuilder {`)
expect(result).to.contain(
`complexOperation(data: Tuple1, value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`
)

expect(result).to.contain(
`EvmEncodeParam.fromValues('()[]', orders.map<EvmEncodeParam>((s0) => EvmEncodeParam.fromValues('()', s0.toEvmEncodeParams())))`
Expand Down Expand Up @@ -841,7 +847,7 @@ describe('AbisInterfaceGenerator', () => {
`batchOperations(addressMatrix: ${LibTypes.Address}[][], valueMatrix: ${LibTypes.BigInt}[][], flagMatrix: ${AssemblyPrimitiveTypes.bool}[][]): EvmCallBuilder {`
)
expect(result).to.contain(
`processMatrix(data: ${LibTypes.Bytes}[][], ids: ${LibTypes.BigInt}[][], value: ${LibTypes.BigInt}): EvmCallBuilder {`
`processMatrix(data: ${LibTypes.Bytes}[][], ids: ${LibTypes.BigInt}[][], value: ${LibTypes.BigInt} = ${LibTypes.BigInt}.zero()): EvmCallBuilder {`
)

expect(result).to.contain(
Expand All @@ -868,7 +874,7 @@ describe('AbisInterfaceGenerator', () => {

expect(result).to.contain('static encodeGetBalance(owner: Address): Bytes {')
expect(result).to.contain('static decodeGetBalance(encodedResponse: string): BigInt {')
expect(result).to.contain('getBalance(owner: Address): Result<BigInt, string> {')
expect(result).to.contain('getBalance(owner: Address): _Result<BigInt, string> {')
})

it('should generate encoded data method for write functions', () => {
Expand All @@ -892,7 +898,7 @@ describe('AbisInterfaceGenerator', () => {
const result = AbisInterfaceGenerator.generate(abi, CONTRACT_NAME)

expect(result).to.contain('static encodeValidate(data: Bytes): Bytes {')
expect(result).to.contain('validate(data: Bytes): Result<Void, string> {')
expect(result).to.contain('validate(data: Bytes): _Result<Void, string> {')
expect(result).not.to.contain('_decodeValidateResponse')
})

Expand All @@ -906,9 +912,9 @@ describe('AbisInterfaceGenerator', () => {

// Read function should call both helpers
expect(result).to.contain(`const encodedData = ${CONTRACT_NAME}Utils.encodeGetValue()`)
expect(result).to.contain(`if (response.isError) return Result.err<${LibTypes.BigInt}, string>(response.error)`)
expect(result).to.contain(`if (response.isError) return _Result.err<${LibTypes.BigInt}, string>(response.error)`)
expect(result).to.contain(`const decoded = ${CONTRACT_NAME}Utils.decodeGetValue(response.unwrap())`)
expect(result).to.contain(`return Result.ok<${LibTypes.BigInt}, string>(decoded)`)
expect(result).to.contain(`return _Result.ok<${LibTypes.BigInt}, string>(decoded)`)

// Write function should call encoded data helper
expect(result).to.contain(`const encodedData = ${CONTRACT_NAME}Utils.encodeSetValue(value)`)
Expand Down