@@ -14,17 +14,17 @@ import { Message } from '../../../interfaces/userRequest'
1414import { AccountOp } from '../../accountOp/accountOp'
1515import { Call } from '../../accountOp/types'
1616import {
17+ HumanizerCallModule ,
1718 HumanizerErc7730Row ,
1819 HumanizerErc7730Visualization ,
19- HumanizerCallModule ,
2020 HumanizerMeta ,
2121 HumanizerVisualization ,
2222 HumanizerWarning ,
2323 IrCall ,
2424 IrMessage
2525} from '../interfaces'
26- import AllowanceModule , { getSetAllowanceResetText } from '../modules/Allowance'
2726import { aaveHumanizer } from '../modules/Aave'
27+ import AllowanceModule , { getSetAllowanceResetText } from '../modules/Allowance'
2828import { decodeGeneralAdapterCall } from '../modules/Bundler3/generalAdapter'
2929import { getDelegateCallWarning , getSafeHumanization } from '../modules/Safe'
3030import { genericErc20Humanizer } from '../modules/Tokens'
@@ -34,9 +34,9 @@ import {
3434 getChain ,
3535 getErc7730Visualization ,
3636 getText ,
37- getToken
37+ getToken ,
38+ uintToAddress
3839} from '../utils'
39- import { getAbiBytesCalldataWithPadding , multiSendInterface } from './calldata'
4040import { SAFE_TX_PRIMARY_TYPE } from './consts'
4141import { getEip712EncodeType , getEip712EncodeTypeHashFromString } from './eip712'
4242import {
@@ -71,6 +71,7 @@ type VisibilityResult = {
7171
7272const MAX_INTERPOLATED_VALUE_LENGTH = 80
7373const MAX_NESTED_CALLDATA_DEPTH = 4
74+ const ABI_WORD_HEX_LENGTH = 64
7475
7576const isMapReference = ( value : unknown ) : value is Erc7730MapReference =>
7677 isPlainObject ( value ) && typeof value . map === 'string' && typeof value . keyPath === 'string'
@@ -129,6 +130,15 @@ const getPathSegments = (path: string): string[] => {
129130const normalizeSegmentIndex = ( index : number , length : number ) : number =>
130131 index < 0 ? length + index : index
131132
133+ const bigintToAbiWordHex = ( value : bigint ) : string | null => {
134+ if ( value < 0n ) return null
135+
136+ const hex = value . toString ( 16 )
137+ if ( hex . length > ABI_WORD_HEX_LENGTH ) return null
138+
139+ return hex . padStart ( ABI_WORD_HEX_LENGTH , '0' )
140+ }
141+
132142const readBracketSegment = ( source : unknown , segment : string ) : unknown => {
133143 if ( ! segment . startsWith ( '[' ) || ! segment . endsWith ( ']' ) ) return undefined
134144
@@ -143,9 +153,17 @@ const readBracketSegment = (source: unknown, segment: string): unknown => {
143153 }
144154
145155 if ( separatorIndex === bracketContent . lastIndexOf ( ':' ) ) {
146- if ( typeof source !== 'string' ) return undefined
156+ const hex =
157+ typeof source === 'string'
158+ ? source . startsWith ( '0x' )
159+ ? source . slice ( 2 )
160+ : source
161+ : typeof source === 'bigint'
162+ ? bigintToAbiWordHex ( source )
163+ : null
164+
165+ if ( hex === null ) return undefined
147166
148- const hex = source . startsWith ( '0x' ) ? source . slice ( 2 ) : source
149167 if ( hex . length % 2 !== 0 ) return undefined
150168
151169 const startText = bracketContent . slice ( 0 , separatorIndex )
@@ -483,6 +501,15 @@ const getTokenAddressFromField = (
483501 const tokenAddress = tokenPath ?? tokenParam
484502
485503 if ( hasTokenSource && isNativeTokenReference ( tokenAddress ) ) return ZeroAddress
504+ if ( typeof tokenAddress === 'bigint' ) {
505+ const uintAddress = uintToAddress ( tokenAddress )
506+
507+ return nativeAddresses . some (
508+ ( address ) => eToNative ( address ) . toLowerCase ( ) === eToNative ( uintAddress ) . toLowerCase ( )
509+ )
510+ ? ZeroAddress
511+ : eToNative ( uintAddress )
512+ }
486513 if ( typeof tokenAddress !== 'string' || ! isAddress ( tokenAddress ) ) return null
487514
488515 return nativeAddresses . some (
@@ -521,7 +548,9 @@ const getEnumValue = (
521548 if ( ! isPlainObject ( enumDefinition ) ) return null
522549
523550 const values = isPlainObject ( enumDefinition . values ) ? enumDefinition . values : enumDefinition
524- const enumValue = values [ valueToText ( value ) ]
551+ const enumKey =
552+ typeof value === 'string' && isHexString ( value ) ? toBigIntOrNull ( value ) ?. toString ( ) : undefined
553+ const enumValue = values [ enumKey || valueToText ( value ) ]
525554
526555 return typeof enumValue === 'string' ? enumValue : null
527556}
@@ -533,6 +562,8 @@ const formatFieldValue = (
533562 base : unknown
534563) : HumanizerVisualization [ ] => {
535564 if ( field . format === 'addressName' || field . format === 'interoperableAddressName' ) {
565+ if ( typeof value === 'bigint' ) return [ getAddressVisualization ( uintToAddress ( value ) ) ]
566+
536567 return typeof value === 'string' && isAddress ( value )
537568 ? [ getAddressVisualization ( value ) ]
538569 : [ getText ( valueToText ( value ) ) ]
@@ -670,7 +701,7 @@ const getCalldataRows = (
670701 const amountValues = resolveCalldataParam ( field , context , base , 'amountPath' , 'amount' )
671702 const accountAddr = resolvePath ( '#.@.accountAddr' , context , context . root )
672703 const nestedRowLabel =
673- field . label ?. trim ( ) . toLowerCase ( ) === 'call' ? '' : field . label ?? field . path ?? ''
704+ field . label ?. trim ( ) . toLowerCase ( ) === 'call' ? '' : ( field . label ?? field . path ?? '' )
674705
675706 return values . reduce < HumanizerErc7730Row [ ] | null > ( ( acc , calldata , index ) => {
676707 if ( ! acc ) return null
@@ -875,6 +906,76 @@ const formatToVisualizations = (
875906 return [ getErc7730Visualization ( intent , rows , dapp ) ]
876907}
877908
909+ const isOneInchFillOrderFormat = ( formatKey : string , descriptorPath ?: string ) =>
910+ ! ! descriptorPath ?. includes ( 'registry/1inch/' ) && formatKey . startsWith ( 'fillOrder(' )
911+
912+ const getUintAddressValue = ( value : unknown ) : string | null => {
913+ if ( typeof value === 'bigint' ) return uintToAddress ( value )
914+ if ( typeof value === 'string' && isAddress ( value ) ) return value
915+
916+ return null
917+ }
918+
919+ const getOneInchFillOrderSwapVisualization = (
920+ match : DescriptorFormatMatch ,
921+ context : FormatContext ,
922+ fullVisualization : HumanizerVisualization [ ] ,
923+ dapp ?: Call [ 'dapp' ]
924+ ) : HumanizerVisualization [ ] | null => {
925+ if ( ! isOneInchFillOrderFormat ( match . formatKey , context . descriptorPath ) ) return fullVisualization
926+
927+ const order = match . values . order
928+ if ( ! isPlainObject ( order ) ) return fullVisualization
929+
930+ const maker = getUintAddressValue ( order . maker )
931+ const makerAsset = getUintAddressValue ( order . makerAsset )
932+ const takerAsset = getUintAddressValue ( order . takerAsset )
933+ const makingAmount = toBigIntOrNull ( order . makingAmount )
934+ const takingAmount = toBigIntOrNull ( order . takingAmount )
935+
936+ if ( ! maker || ! makerAsset || ! takerAsset || makingAmount === null || takingAmount === null ) {
937+ return fullVisualization
938+ }
939+
940+ const metadata = context . root [ '@' ]
941+ const accountAddr = isPlainObject ( metadata ) ? metadata . accountAddr : undefined
942+ const isMakerAccount =
943+ typeof accountAddr === 'string' && maker . toLowerCase ( ) === accountAddr . toLowerCase ( )
944+ const outgoingToken = isMakerAccount ? makerAsset : takerAsset
945+ const outgoingAmount = isMakerAccount ? makingAmount : toBigIntOrNull ( match . values . amount )
946+ const incomingToken = isMakerAccount ? takerAsset : makerAsset
947+ const incomingAmount = isMakerAccount ? takingAmount : makingAmount
948+
949+ if ( outgoingAmount === null ) return fullVisualization
950+
951+ const oneInchVisualization = fullVisualization . find (
952+ ( visualization ) : visualization is HumanizerVisualization & HumanizerErc7730Visualization =>
953+ visualization . type === 'erc7730'
954+ )
955+ const additionalRows =
956+ oneInchVisualization ?. rows . filter (
957+ ( row ) => ! row . value . some ( ( value ) => value . type === 'token' )
958+ ) || [ ]
959+
960+ return [
961+ getErc7730Visualization (
962+ oneInchVisualization ?. title || 'Fill order' ,
963+ [
964+ {
965+ label : 'Amount to Send' ,
966+ value : [ getToken ( outgoingToken , outgoingAmount , context . chainId ) ]
967+ } ,
968+ {
969+ label : 'Minimum to Receive' ,
970+ value : [ getToken ( incomingToken , incomingAmount , context . chainId ) ]
971+ } ,
972+ ...additionalRows
973+ ] ,
974+ dapp
975+ )
976+ ]
977+ }
978+
878979const getSafeTxCallFromMessage = ( message : Message ) : Call | null => {
879980 if ( message . content . kind !== 'typedMessage' ) return null
880981 if ( message . content . primaryType !== SAFE_TX_PRIMARY_TYPE ) return null
@@ -1005,14 +1106,12 @@ const getSafeCallFallbackVisualization = (
10051106 ? { ...visualization , content : String ( visualization . content ) }
10061107 : visualization
10071108 )
1008- const rows : HumanizerErc7730Row [ ] = value . length
1009- ? [
1010- {
1011- label : action . content ,
1012- value
1013- }
1014- ]
1015- : [ ]
1109+ const rows : HumanizerErc7730Row [ ] = [
1110+ {
1111+ label : action . content ,
1112+ value : value . length || ! call . to ? value : [ getAddressVisualization ( call . to ) ]
1113+ }
1114+ ]
10161115 if ( ! rows . length ) return null
10171116
10181117 const visualization = getErc7730Visualization ( action . content , rows )
@@ -1285,11 +1384,14 @@ export const humanizeCallWithErc7730 = (
12851384 nestedCalldataDepth
12861385 }
12871386 const fullVisualization = formatToVisualizations ( match . format , context , call . dapp )
1387+ const normalizedVisualization = fullVisualization
1388+ ? getOneInchFillOrderSwapVisualization ( match , context , fullVisualization , call . dapp )
1389+ : null
12881390
1289- return fullVisualization ?. length
1391+ return normalizedVisualization ?. length
12901392 ? {
12911393 ...call ,
1292- fullVisualization,
1394+ fullVisualization : normalizedVisualization ,
12931395 warnings : dedupeWarnings ( getSafeCallWarnings ( call , accountAddr ) )
12941396 }
12951397 : null
0 commit comments