Introduction
This guide focusses on the most common patterns of interactions with the Bounty Manager Module. Please refer to the Technical Reference section to see all public getters and setters.
The guide includes code snippets for both Inverter Network's TypeScript SDK and React SDK. Please refer to the relevant code snippets based on the SDK you are using.
Setup Requirements
Managing Bounty Manager Roles
Managing roles for the Bounty Manager involves several steps, including reading role, generating role IDs, assigning roles, and revoking them.
Retrieving the roles
The Bounty Manager utilizes several roles to handle the issuance, verification, and claiming of bounties. The first step is to retrieve the available roles in the Bounty Manager, as demonstrated below:
TS SDK
Copy const VERIFIER_ROLE = await workflow . optionalModule . LM_PC_Bounties_v1 . read . VERIFIER_ROLE .run ()
const BOUNTY_ISSUER_ROLE = await workflow . optionalModule . LM_PC_Bounties_v1 . read . BOUNTY_ISSUER_ROLE .run ()
const CLAIMANT_ROLE = await workflow . optionalModule . LM_PC_Bounties_v1 . read . CLAIMANT_ROLE .run ()
React SDK
Copy // Combined query for fetching all roles
const rolesQuery = useQuery ({
queryKey : [ 'roles' ] ,
enabled : !! workflow .data ,
queryFn : async () => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
const VERIFIER_ROLE = await workflow . data . optionalModule . LM_PC_Bounties_v1 . read . VERIFIER_ROLE .run ()
const BOUNTY_ISSUER_ROLE = await workflow . data . optionalModule . LM_PC_Bounties_v1 . read . BOUNTY_ISSUER_ROLE .run ()
const CLAIMANT_ROLE = await workflow . data . optionalModule . LM_PC_Bounties_v1 . read . CLAIMANT_ROLE .run ()
return {
VERIFIER_ROLE ,
BOUNTY_ISSUER_ROLE ,
CLAIMANT_ROLE
}
}
})
Check If User Has Module Roles
The following two-step process validates whether a given address has roles assigned to it:
TS SDK
Copy // Step 1. Generate the role ids
const [ GEN_VERIFIER_ROLE , GEN_BOUNTY_ISSUER_ROLE , GEN_CLAIMANT_ROLE ] =
await Promise .all (
[ VERIFIER_ROLE , BOUNTY_ISSUER_ROLE , CLAIMANT_ROLE ] .map ((id) => {
return workflow . authorizer . read . generateRoleId .run ([
workflow . optionalModule . LM_PC_Bounties_v1 .address ,
id ,
])
})
)
// Step 2. Check if the user has the role
const [ HAS_VERIFIER_ROLE , HAS_BOUNTY_ISSUER_ROLE , HAS_CLAIMANT_ROLE ] =
await Promise .all (
[ GEN_VERIFIER_ROLE , GEN_BOUNTY_ISSUER_ROLE , GEN_CLAIMANT_ROLE ] .map (
(genId) => {
return workflow . authorizer . read . hasRole .run ([
genId ,
< wallet_address > ,
])
}
)
)
React SDK
Copy // Combined query for generating role IDs
const generatedRoleIdsQuery = useQuery ({
queryKey : [ 'generatedRoleIds' , rolesQuery .dataUpdatedAt] ,
enabled : !! workflow .data && !! rolesQuery .data ,
queryFn : async () => {
if ( ! workflow .data || ! rolesQuery .data) throw new Error ( 'Required data not available' )
const roleIds = [
rolesQuery . data . VERIFIER_ROLE ,
rolesQuery . data . BOUNTY_ISSUER_ROLE ,
rolesQuery . data . CLAIMANT_ROLE
]
const generatedIds = await Promise .all (
roleIds .map ((id) => {
return workflow . data . authorizer . read . generateRoleId .run ([
workflow . data . optionalModule . LM_PC_Bounties_v1 .address ,
id ,
])
})
)
return generatedIds
}
})
// Combined query for checking user roles
const userRolesQuery = useQuery ({
queryKey : [ 'userRoles' , generatedRoleIdsQuery .dataUpdatedAt , '<wallet_address>' ] ,
enabled : !! workflow .data && !! generatedRoleIdsQuery .data ,
queryFn : async () => {
if ( ! workflow .data || ! generatedRoleIdsQuery .data) throw new Error ( 'Required data not available' )
const [
GEN_VERIFIER_ROLE ,
GEN_BOUNTY_ISSUER_ROLE ,
GEN_CLAIMANT_ROLE
] = generatedRoleIdsQuery .data
const hasRoles = await Promise .all (
roleIds .map ((genId) => {
return workflow . data . authorizer . read . hasRole .run ([
genId ,
'<wallet_address>' ,
])
})
)
return hasRoles
}
})
Grant and Revoke Role
The following section demonstrates how to grant and revoke roles for a wallet address.
TS SDK
Copy const walletAddress = sdk . walletClient . account .address
const args = [
< VERIFIER_ROLE | BOUNTY_ISSUER_ROLE | CLAIMANT_ROLE > ,
walletAddress
] as const
// Grant role
const grantRoleTransactionHash = await workflow . optionalModule . LM_PC_Bounties_v1 . write . grantModuleRole .run (args)
// Revoke role
const revokeRoleTransactionHash = await workflow . optionalModule . LM_PC_Bounties_v1 . write . revokeModuleRole .run (args)
React SDK
Copy // Mutation for granting roles
const grantRoleMutation = useMutation ({
mutationFn : async ({ role , walletAddress } : { role : NonNullable < rolesQuery [ 'data' ][ number ]> , walletAddress : `0x ${ string } ` }) => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
const args = [role , walletAddress] as const
return await workflow . data . optionalModule . LM_PC_Bounties_v1 . write . grantModuleRole .run (args)
}
})
// Mutation for revoking roles
const revokeRoleMutation = useMutation ({
mutationFn : async ({ role: NonNullable<rolesQuery[ 'data' ][number]> , walletAddress: `0x ${ string } ` }) => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
const args = [role , walletAddress] as const
return await workflow . data . optionalModule . LM_PC_Bounties_v1 . write . revokeModuleRole .run (args)
}
})
Bounty Creation
Add a Bounty
The following section explains how to add a bounty to the Bounty Manager:
TS SDK
Copy import { decodeEventLog , parseAbiItem } from 'viem'
let bountyId = string
const addBountyTransactionHash = await workflow . optionalModule . LM_PC_Bounties_v1 . write . addBounty .run ([
// Minimum Payment Amount
'1000' ,
// Maximum Payment Amount
'10000' ,
// Details ( type any )
{
timestamp : 1734448333
message: 'hello'
}
] , {
confirmations : 1 ,
// !Optional! You can get the list of bounty id's from a different endpoint
onConfirmation : (receipt) => {
// Define the ABI for the BountyAdded event
const addBountyOutputAbi = parseAbiItem (
'event BountyAdded(uint256 indexed bountyId, uint256 minimumPayoutAmount, uint256 maximumPayoutAmount, bytes details)'
)
// Decode the logs using the ABI
const decodedLogs = decodeEventLog ({
abi : [addBountyOutputAbi] ,
data : receipt .logs[ 0 ].data ,
topics : receipt .logs[ 0 ].topics ,
})
// Retrieve the bountyId from the decoded logs
bountyId = decodedLogs . args . bountyId .toString ()
} ,
})
React SDK
Copy // Add Single Bounty Mutation
const addBountyMutation = useMutation ({
mutationFn : async ({ minAmount , maxAmount , details }) => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
let bountyId = string
const transactionHash = await workflow . data . optionalModule . LM_PC_Bounties_v1 . write . addBounty .run (
[minAmount , maxAmount , details] ,
{
confirmations : 1 ,
onConfirmation : (receipt) => {
const addBountyOutputAbi = parseAbiItem (
'event BountyAdded(uint256 indexed bountyId, uint256 minimumPayoutAmount, uint256 maximumPayoutAmount, bytes details)'
)
const decodedLogs = decodeEventLog ({
abi : [addBountyOutputAbi] ,
data : receipt .logs[ 0 ].data ,
topics : receipt .logs[ 0 ].topics ,
})
bountyId = decodedLogs . args . bountyId .toString ()
} ,
}
)
return { transactionHash , bountyId }
}
})
Add Bounty in Batches
The following section explains how to add multiple bounties in batches
TS SDK
Copy import { decodeEventLog , parseAbiItem } from 'viem'
let bountyDetails = [
// Minimum Payment Amounts
[ '1000`, ' 2000 ', ' 3000 '],
// Maximum Payment Amount
[ '10000' , '20000' , '30000' ] ,
// Details ( type any )
[{
timestamp : 1734448333
message: 'hello'
} ,
{
timestamp : 1734448334
message: 'hello1'
} ,
{
timestamp : 1734448335
message: 'hello2'
}]
] as const
const addBountyTransactionHash = await workflow . optionalModule . LM_PC_Bounties_v1 . write . addBountyBatch .run (bountyDetails)
React SDK
Copy // Add Batch Bounties Mutation
const addBountyBatchMutation = useMutation ({
mutationFn : async (bountyDetails) => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
return await workflow . data . optionalModule . LM_PC_Bounties_v1 . write . addBountyBatch .run (
bountyDetails
)
}
})
Read Bounty
The following section explains how to read a given bounty information based on the bountyId
TS SDK
Copy const bountyInformation = await workflow . optionalModule . LM_PC_Bounties_v1 . read . getBountyInformation .run (bountyId)
const {
minimumPayoutAmount
maximumPayoutAmount
details: {
timestamp ,
message
}
locked
} = bountyInformation
console .log (bountyInformation)
React SDK
Copy // Get Bounty Information Query
const useBountyInformation = (bountyId) => useQuery ({
queryKey : [ 'bountyInformation' , bountyId] ,
enabled : !! bountyId && !! workflow .data ,
queryFn : async () => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
return await workflow . data . optionalModule . LM_PC_Bounties_v1 . read . getBountyInformation .run (bountyId)
}
})
Bounty Claim
Add Bounty Claim
The following section explains how to submit a bounty claim:
TS SDK
Copy import { decodeEventLog , parseAbiItem } from 'viem'
let claimId = string
const contributers =
[
// Bounty Id
bountyId ,
// Contributers
[{ addr : sdk . walletClient . account .address , claimAmount : '100' }] ,
// Details ( type any )
{
claimUrl : 'https://www.google.com' ,
} ,
] as const
const claimTransactionHash = await workflow . optionalModule . LM_PC_Bounties_v1 . write . addClaim .run (
contributers ,
{
confirmations : 1 ,
// !Optional! You can get the list of claim id's from a different endpoint
onConfirmation : (receipt) => {
const claimAddedAbi = parseAbiItem (
'event ClaimAdded(uint256 indexed claimId,uint256 indexed bountyId,(address,uint256)[] contributors,bytes details)'
)
const decodedLogs = decodeEventLog ({
abi : [claimAddedAbi] ,
data : receipt .logs[ 0 ].data ,
topics : receipt .logs[ 0 ].topics ,
})
claimId = decodedLogs . args . claimId .toString ()
} ,
}
)
React SDK
Copy // Add Claim Mutation
const addClaimMutation = useMutation ({
mutationFn : async ({ bountyId , contributors , details }) => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
let bountyId : string
const transactionHash = await workflow . data . optionalModule . LM_PC_Bounties_v1 . write . addClaim .run (
[bountyId , contributors , details] ,
{
confirmations : 1 ,
onConfirmation : (receipt) => {
const claimAddedAbi = parseAbiItem (
'event ClaimAdded(uint256 indexed claimId,uint256 indexed bountyId,(address,uint256)[] contributors,bytes details)'
)
const decodedLogs = decodeEventLog ({
abi : [claimAddedAbi] ,
data : receipt .logs[ 0 ].data ,
topics : receipt .logs[ 0 ].topics ,
})
return decodedLogs . args . claimId .toString ()
} ,
}
)
return { transactionHash , bountyId }
}
})
Read Bounty Claim
The following section explains how to read a submitted bounty claim
TS SDK
Copy const claimInformation = await workflow . optionalModule . LM_PC_Bounties_v1 . read . getClaimInformation .run (claimId)
const {
details: { claimUrl } ,
bountyId ,
claimed ,
contributors ,
} = claimInformation
console .log (claimInformation)
React SDK
Copy // Get Claim Information Query
const useClaimInformation = (claimId) => useQuery ({
queryKey : [ 'claimInformation' , claimId] ,
enabled : !! claimId && !! workflow .data ,
queryFn : async () => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
return await workflow . data . optionalModule . LM_PC_Bounties_v1 . read . getClaimInformation .run (claimId)
}
})
Verify Bounty Claim
Verify a Claim
The following section explains how to verify a claim providing the claimId
and contributors
as parameters:
TS SDK
Copy const hash = await workflow . optionalModule . LM_PC_Bounties_v1 . write . verifyClaim .run ([
claimId ,
contributors ,
])
React SDK
Copy // Verify Claim Mutation
const verifyClaimMutation = useMutation ({
mutationFn : async ({ claimId , contributors }) => {
if ( ! workflow .data) throw new Error ( 'No workflow instance found' )
return await workflow . data . optionalModule . LM_PC_Bounties_v1 . write . verifyClaim .run ([
claimId ,
contributors ,
])
}
})
return {
addBountyMutation ,
addBountyBatchMutation ,
useBountyInformation ,
addClaimMutation ,
useClaimInformation ,
verifyClaimMutation
}
}