@@ -29,7 +29,24 @@ type CampaignStruct = ReturnType<typeof abi.events.NewCampaign.decode>['campaign
2929 * so Subsquid retries it later — no partial/null data is ever written, and the processor
3030 * pauses rather than crashing.
3131 */
32- type ResolvedCampaign = { targetToken : string | null ; rewardTokenDecimals : number }
32+ type ResolvedCampaign = {
33+ targetToken : string | null
34+ rewardTokenDecimals : number
35+ distributionMethod : string | null
36+ aprCap : number | null
37+ }
38+
39+ type MerklCampaignApi = {
40+ campaignId ?: string
41+ params ?: {
42+ targetToken ?: string
43+ decimalsRewardToken ?: number
44+ distributionMethodParameters ?: {
45+ distributionMethod ?: string
46+ distributionSettings ?: { apr ?: string | number }
47+ }
48+ }
49+ }
3350
3451const resolveCampaign = async ( ctx : Context , chainId : number , campaignId : string ) : Promise < ResolvedCampaign > => {
3552 // test=true includes test campaigns in the response (additive — live campaigns still returned).
@@ -41,12 +58,19 @@ const resolveCampaign = async (ctx: Context, chainId: number, campaignId: string
4158 try {
4259 const res = await fetch ( url )
4360 if ( ! res . ok ) throw new Error ( `status ${ res . status } ` )
44- const data = ( await res . json ( ) ) as { campaignId ?: string ; params ?: { targetToken ?: string ; decimalsRewardToken ?: number } } [ ]
61+ const data = ( await res . json ( ) ) as MerklCampaignApi [ ]
4562 const match = data . find ( ( c ) => c ?. campaignId ?. toLowerCase ( ) === campaignId . toLowerCase ( ) )
4663 if ( ! match ) throw new Error ( 'campaign not yet indexed by Merkl' )
64+ const dist = match . params ?. distributionMethodParameters
65+ // MAX_APR campaigns cap the reward rate; distributionSettings.apr is the cap (e.g. "0.02").
66+ const aprCap = dist ?. distributionMethod === 'MAX_APR' && dist . distributionSettings ?. apr != null
67+ ? Number ( dist . distributionSettings . apr )
68+ : null
4769 return {
4870 targetToken : match . params ?. targetToken ?. toLowerCase ( ) ?? null ,
4971 rewardTokenDecimals : match . params ?. decimalsRewardToken ?? 18 ,
72+ distributionMethod : dist ?. distributionMethod ?? null ,
73+ aprCap : Number . isFinite ( aprCap ) ? aprCap : null ,
5074 }
5175 } catch ( err ) {
5276 lastError = err
@@ -77,7 +101,11 @@ const upsertFromStruct = async (
77101 if ( ! creatorSet . has ( campaign . creator . toLowerCase ( ) ) ) return
78102
79103 const id = `${ ctx . chain . id } :${ campaign . campaignId } `
80- const { targetToken, rewardTokenDecimals } = await resolveCampaign ( ctx , ctx . chain . id , campaign . campaignId )
104+ const { targetToken, rewardTokenDecimals, distributionMethod, aprCap } = await resolveCampaign (
105+ ctx ,
106+ ctx . chain . id ,
107+ campaign . campaignId ,
108+ )
81109 const timestamp = new Date ( block . header . timestamp )
82110 const existing = campaigns . get ( id ) ?? ( await ctx . store . get ( MerklCampaign , id ) )
83111
@@ -97,6 +125,8 @@ const upsertFromStruct = async (
97125
98126 // Resolved target (Merkl API), and the ARM it rewards when the target is one of ours.
99127 entity . rewardTokenDecimals = rewardTokenDecimals
128+ entity . distributionMethod = distributionMethod
129+ entity . aprCap = aprCap
100130 entity . targetToken = targetToken
101131 entity . armAddress = targetToken && armSet . has ( targetToken ) ? targetToken : null
102132 // Mutable fields (overrideCampaign can change start/duration/campaignData).
0 commit comments