@@ -10,6 +10,8 @@ import {
1010 SignatureOfSapientSignerLeaf ,
1111 SignatureOfSignerLeaf ,
1212} from './signature.js'
13+ import { hash as hashPayload } from './payload.js'
14+ import type { Parented } from './payload.js'
1315import { Constants } from './index.js'
1416
1517export type SignerLeaf = {
@@ -104,6 +106,19 @@ export type Config = {
104106 checkpointer ?: Address . Address
105107}
106108
109+ export type TopologyWeightContext = {
110+ wallet : Address . Address
111+ chainId : number
112+ payload : Parented
113+ }
114+
115+ export const MATCHING_SUBDIGEST_WEIGHT = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn
116+
117+ type ResolvedTopologyWeightContext = {
118+ digest : Bytes . Bytes
119+ anyAddressDigest : Bytes . Bytes
120+ }
121+
107122export function isSignerLeaf ( cand : unknown ) : cand is SignerLeaf {
108123 return typeof cand === 'object' && cand !== null && 'type' in cand && cand . type === 'signer'
109124}
@@ -209,6 +224,41 @@ export function findSignerLeaf(
209224export function getWeight (
210225 topology : RawTopology | RawConfig | Config ,
211226 canSign : ( signer : SignerLeaf | SapientSignerLeaf ) => boolean ,
227+ context ?: TopologyWeightContext ,
228+ ) : { weight : bigint ; maxWeight : bigint } {
229+ return getWeightWithContext ( topology , canSign , resolveTopologyWeightContext ( context ) )
230+ }
231+
232+ function resolveTopologyWeightContext ( context ?: TopologyWeightContext ) : ResolvedTopologyWeightContext | undefined {
233+ if ( ! context ) {
234+ return undefined
235+ }
236+
237+ return {
238+ digest : hashPayload ( context . wallet , context . chainId , context . payload ) ,
239+ anyAddressDigest : hashPayload ( Constants . ZeroAddress , context . chainId , context . payload ) ,
240+ }
241+ }
242+
243+ function getSubdigestWeight (
244+ topology : SubdigestLeaf | AnyAddressSubdigestLeaf ,
245+ context ?: ResolvedTopologyWeightContext ,
246+ ) : bigint {
247+ if ( ! context ) {
248+ return 0n
249+ }
250+
251+ if ( isSubdigestLeaf ( topology ) ) {
252+ return Bytes . isEqual ( Bytes . fromHex ( topology . digest ) , context . digest ) ? MATCHING_SUBDIGEST_WEIGHT : 0n
253+ }
254+
255+ return Bytes . isEqual ( Bytes . fromHex ( topology . digest ) , context . anyAddressDigest ) ? MATCHING_SUBDIGEST_WEIGHT : 0n
256+ }
257+
258+ function getWeightWithContext (
259+ topology : RawTopology | RawConfig | Config ,
260+ canSign : ( signer : SignerLeaf | SapientSignerLeaf ) => boolean ,
261+ context ?: ResolvedTopologyWeightContext ,
212262) : { weight : bigint ; maxWeight : bigint } {
213263 topology = isRawConfig ( topology ) || isConfig ( topology ) ? topology . topology : topology
214264
@@ -223,19 +273,24 @@ export function getWeight(
223273 } else if ( isSapientSignerLeaf ( topology ) ) {
224274 return { weight : 0n , maxWeight : canSign ( topology ) ? topology . weight : 0n }
225275 } else if ( isSubdigestLeaf ( topology ) ) {
226- return { weight : 0n , maxWeight : 0n }
276+ const weight = getSubdigestWeight ( topology , context )
277+ return { weight, maxWeight : weight }
227278 } else if ( isAnyAddressSubdigestLeaf ( topology ) ) {
228- return { weight : 0n , maxWeight : 0n }
279+ const weight = getSubdigestWeight ( topology , context )
280+ return { weight, maxWeight : weight }
229281 } else if ( isRawNestedLeaf ( topology ) ) {
230- const { weight, maxWeight } = getWeight ( topology . tree , canSign )
282+ const { weight, maxWeight } = getWeightWithContext ( topology . tree , canSign , context )
231283 return {
232284 weight : weight >= topology . threshold ? topology . weight : 0n ,
233285 maxWeight : maxWeight >= topology . threshold ? topology . weight : 0n ,
234286 }
235287 } else if ( isNodeLeaf ( topology ) ) {
236288 return { weight : 0n , maxWeight : 0n }
237289 } else {
238- const [ left , right ] = [ getWeight ( topology [ 0 ] , canSign ) , getWeight ( topology [ 1 ] , canSign ) ]
290+ const [ left , right ] = [
291+ getWeightWithContext ( topology [ 0 ] , canSign , context ) ,
292+ getWeightWithContext ( topology [ 1 ] , canSign , context ) ,
293+ ]
239294 return { weight : left . weight + right . weight , maxWeight : left . maxWeight + right . maxWeight }
240295 }
241296}
@@ -250,26 +305,27 @@ function stripSignedState(leaf: SignerLeaf | SapientSignerLeaf): SignerLeaf | Sa
250305 return rest
251306}
252307
253- function buildMinimisedTopologyPlans ( topology : Topology ) : Array < MinimisedTopologyPlan | undefined > {
308+ function buildMinimisedTopologyPlans (
309+ topology : Topology ,
310+ context ?: ResolvedTopologyWeightContext ,
311+ ) : Array < MinimisedTopologyPlan | undefined > {
254312 if ( isSignedSignerLeaf ( topology ) || isSignedSapientSignerLeaf ( topology ) ) {
255313 return [
256314 { weight : 0n , topology : stripSignedState ( topology ) } ,
257315 { weight : topology . weight , topology } ,
258316 ]
259317 }
260318
261- if (
262- isSignerLeaf ( topology ) ||
263- isSapientSignerLeaf ( topology ) ||
264- isSubdigestLeaf ( topology ) ||
265- isAnyAddressSubdigestLeaf ( topology ) ||
266- isNodeLeaf ( topology )
267- ) {
319+ if ( isSubdigestLeaf ( topology ) || isAnyAddressSubdigestLeaf ( topology ) ) {
320+ return [ { weight : getSubdigestWeight ( topology , context ) , topology } ]
321+ }
322+
323+ if ( isSignerLeaf ( topology ) || isSapientSignerLeaf ( topology ) || isNodeLeaf ( topology ) ) {
268324 return [ { weight : 0n , topology } ]
269325 }
270326
271327 if ( isNestedLeaf ( topology ) ) {
272- return buildMinimisedTopologyPlans ( topology . tree ) . map ( ( plan ) => {
328+ return buildMinimisedTopologyPlans ( topology . tree , context ) . map ( ( plan ) => {
273329 if ( ! plan ) {
274330 return undefined
275331 }
@@ -285,8 +341,8 @@ function buildMinimisedTopologyPlans(topology: Topology): Array<MinimisedTopolog
285341 }
286342
287343 if ( isNode ( topology ) ) {
288- const leftPlans = buildMinimisedTopologyPlans ( topology [ 0 ] )
289- const rightPlans = buildMinimisedTopologyPlans ( topology [ 1 ] )
344+ const leftPlans = buildMinimisedTopologyPlans ( topology [ 0 ] , context )
345+ const rightPlans = buildMinimisedTopologyPlans ( topology [ 1 ] , context )
290346 const plans = new Array < MinimisedTopologyPlan | undefined > ( leftPlans . length + rightPlans . length - 1 )
291347
292348 for ( let total = 0 ; total < plans . length ; total ++ ) {
@@ -318,8 +374,8 @@ function buildMinimisedTopologyPlans(topology: Topology): Array<MinimisedTopolog
318374 throw new Error ( 'Invalid topology' )
319375}
320376
321- export function minimiseSignedTopology ( topology : Topology , threshold : bigint ) : Topology {
322- const plans = buildMinimisedTopologyPlans ( topology )
377+ export function minimiseSignedTopology ( topology : Topology , threshold : bigint , context ?: TopologyWeightContext ) : Topology {
378+ const plans = buildMinimisedTopologyPlans ( topology , resolveTopologyWeightContext ( context ) )
323379 return plans . find ( ( plan ) => plan && plan . weight >= threshold ) ?. topology ?? topology
324380}
325381
0 commit comments