Skip to content

Instantly share code, notes, and snippets.

@xstelea
Last active April 23, 2025 21:11
Show Gist options
  • Select an option

  • Save xstelea/e63777eae63531bc2452925a4d42d98d to your computer and use it in GitHub Desktop.

Select an option

Save xstelea/e63777eae63531bc2452925a4d42d98d to your computer and use it in GitHub Desktop.
import { BlueprintInterface } from "@radixdlt/babylon-core-api-sdk";
import { GatewayApiClient } from "@radixdlt/babylon-gateway-api-sdk";
export const gatewayClientImplementation = (gateway: GatewayApiClient) => {
const getComponentInformation = async (
address: string
): Promise<{ packageAddress: string; blueprintName: string } | null> => {
const { items } = await gateway.state.innerClient.stateEntityDetails({
stateEntityDetailsRequest: {
addresses: [address],
},
});
if (!items?.[0]?.details) {
return null;
}
const packageDetails = items[0].details as {
package_address?: string;
blueprint_name?: string;
};
if (packageDetails?.package_address && packageDetails?.blueprint_name) {
return {
packageAddress: packageDetails.package_address,
blueprintName: packageDetails.blueprint_name,
};
}
return null;
};
const getAllEventsForComponent = async (
address: string
): Promise<{
interface: BlueprintInterface;
} | null> => {
const information = await getComponentInformation(address);
if (!information) {
return null;
}
// Todo: Use `exhaustPaginationWithLedgerState` to get all data
const events = await gateway.state.innerClient.packageBlueprintPage({
statePackageBlueprintPageRequest: {
package_address: information.packageAddress,
},
});
return events.items.find((item) => item.name === information.blueprintName)
?.definition as {
interface: BlueprintInterface;
};
};
const stateEntityDetails = async (address: string) => {
const entityData = await gateway.state.innerClient.stateEntityDetails({
stateEntityDetailsRequest: {
addresses: [address],
},
});
return entityData.items[0];
};
return {
getComponentInformation,
getAllEventsForComponent,
stateEntityDetails,
};
};
import {
GatewayApiClient,
RadixNetwork,
} from '@radixdlt/babylon-gateway-api-sdk';
import { gatewayClientImplementation } from './gatewayClientImplementation';
// TODO: Use `exhaustPaginationWithLedgerState` to get all events for a component
export type GatewayModule = ReturnType<typeof GatewayModule>;
export const GatewayModule = ({
gatewayClient,
stokenetGatewayClient,
}: {
gatewayClient?: GatewayApiClient;
stokenetGatewayClient?: GatewayApiClient;
}) => {
const gateway =
gatewayClient ??
GatewayApiClient.initialize({
networkId: RadixNetwork.Mainnet,
applicationName: 'hookah.ing',
applicationVersion: '0.0.1',
});
const stokenetGateway =
stokenetGatewayClient ??
GatewayApiClient.initialize({
networkId: RadixNetwork.Stokenet,
applicationName: 'hookah.ing',
applicationVersion: '0.0.1',
});
const stokenet = gatewayClientImplementation(stokenetGateway);
const mainnet = gatewayClientImplementation(gateway);
const networkAwareGatewayClient = (address: string) =>
address.includes('_tdx_2_') ? stokenet : mainnet;
return {
stateEntityDetails: (address: string) =>
networkAwareGatewayClient(address).stateEntityDetails(address),
getAllEventsForComponent: (address: string) =>
networkAwareGatewayClient(address).getAllEventsForComponent(address),
};
};
export const gatewayModule = GatewayModule({});
import {
BlueprintDefinition,
BlueprintInterface,
} from "@radixdlt/babylon-core-api-sdk";
import { gatewayModule, GatewayModule } from "./../gateway/gatewayModule";
export const TriggerValidator = ({
gatewayModule,
}: {
gatewayModule: GatewayModule;
}) => {
const BLOCKED_EVENTS = ["RemoveMetadataEvent", "SetMetadataEvent"];
const SHARED_EVENTS = [
"RemoveMetadataEvent",
"SetMetadataEvent",
"LockOwnerRoleEvent",
"SetOwnerRoleEvent",
"SetRoleEvent",
];
const isValid = async (emitterAddress: string, eventName: string) => {
try {
const validEvents = await getValidEvents(emitterAddress);
if (!validEvents.includes(eventName)) {
return false;
}
return true;
} catch (error) {
return false;
}
};
const getValidEvents = async (emitterAddress: string) => {
const POOL_EVENTS = [
"ContributionEvent",
"RedemptionEvent",
"WithdrawEvent",
"DepositEvent",
...SHARED_EVENTS,
];
const LOCKER_EVENTS = [
"ClaimEvent",
"RecoverEvent",
"StoreEvent",
...SHARED_EVENTS,
];
const ACCOUNT_EVENTS = [
"AddAuthorizedDepositorEvent",
"DepositEvent",
"PayFeeEvent",
"LockFeeEvent",
"RejectedDepositEvent",
"RemoveAuthorizedDepositorEvent",
"RemoveResourcePreferenceEvent",
"SetDefaultDepositRuleEvent",
"SetResourcePreferenceEvent",
"WithdrawEvent",
...SHARED_EVENTS,
];
const RESOURCE_EVENTS = [
"BurnFungibleResourceEvent",
"BurnNonFungibleResourceEvent",
"MintFungibleResourceEvent",
"MintNonFungibleResourceEvent",
"VaultCreationEvent",
...SHARED_EVENTS,
];
const VALIDATOR_EVENTS = [
"RegisterValidatorEvent",
"UnregisterValidatorEvent",
"StakeEvent",
"UnstakeEvent",
"ClaimXrdEvent",
"UpdateAcceptingStakeDelegationStateEvent",
"ProtocolUpdateReadinessSignalEvent",
"ValidatorEmissionAppliedEvent",
"ValidatorRewardAppliedEvent",
...SHARED_EVENTS,
];
const INTERNAL_VAULT_EVENTS = [
"DepositEvent",
"LockFeeEvent",
"PayFeeEvent",
"RecallEvent",
"WithdrawEvent",
];
const CONSENSUS_MANAGER_EVENTS = [
"EpochChangeEvent",
"RoundChangeEvent",
"DepositEvent",
].filter((event) => !BLOCKED_EVENTS.includes(event));
if (emitterAddress.startsWith("component_")) {
// Check component events from the gateway
const componentEvents = (await gatewayModule.getAllEventsForComponent(
emitterAddress
)) as {
interface: BlueprintInterface;
};
// Return component events if available
if (componentEvents?.interface?.events) {
return [
...Object.keys(componentEvents.interface.events),
...SHARED_EVENTS,
];
}
}
const entityDetails =
await gatewayModule.stateEntityDetails(emitterAddress);
if (!entityDetails || entityDetails.address !== emitterAddress) {
return [];
}
if (emitterAddress.startsWith("pool_")) {
return POOL_EVENTS;
}
if (emitterAddress.startsWith("locker_")) {
return LOCKER_EVENTS;
}
if (emitterAddress.startsWith("account_")) {
return ACCOUNT_EVENTS;
}
if (emitterAddress.startsWith("resource_")) {
return RESOURCE_EVENTS;
}
if (emitterAddress.startsWith("validator_")) {
return VALIDATOR_EVENTS;
}
if (emitterAddress.startsWith("internal_vault_")) {
return INTERNAL_VAULT_EVENTS;
}
if (emitterAddress.startsWith("consensusmanager_")) {
return CONSENSUS_MANAGER_EVENTS;
}
if (emitterAddress.startsWith("package_")) {
const possibleEvents =
entityDetails.details?.type === "Package" &&
entityDetails.details?.blueprints?.items
.map((blueprint) =>
Object.keys(
(
blueprint.definition as {
interface: BlueprintDefinition["_interface"];
}
).interface.events
)
)
.flat()
.filter((value): value is string => typeof value === "string");
if (possibleEvents) {
return possibleEvents;
}
}
return [];
};
return {
getValidEvents,
isValid,
};
};
export const triggerValidator = TriggerValidator({
gatewayModule,
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment