Welcome to FIXeS on-chain interactions documentation
Overview
In this section, we provide detailed instructions on interacting with the FIXeS contract on the blockchain. To effectively interact with the FIXeS contract, users should possess a basic understanding of blockchain technology, smart contracts, and the Flow blockchain that the FIXeS contract is deployed on.
For front-end or NodeJS projects, we have prepared a more user-friendly way of integration. You can follow this guide to get started.
Requirements
Node version v16.0.0 or higher.
FCL(Flow Client Library) installation: Official Doc
Dependencies Installation
Install FIXeS contracts to your application via npm, yarn, or pnpm
npm i @fixes/contracts
yarn add @fixes/contracts
pnpm add @fixes/contracts
Include *.cdc assets for your project
Interacting with the Flow blockchain requires using transactions/scripts, and all necessary ones are included in @fixes/contracts package. However, to use them in your application, you need to make sure that your building tool can recognize this file extension first.
FCL is an all-in-one JS library to interact with Flow blockchain, If you are not familiar with it, you can refer to the code below.
Here is an independent wrapped class of FCL :
/// This is a TypeScript example
/// If some type is not found, you can directly change it to any
import * as fcl from "@onflow/fcl";
import type { Account, TransactionStatus } from "@onflow/typedefs";
export type NetworkType = "mainnet" | "testnet" | "emulator";
let isGloballyInited = false;
let globallyPromise = null;
export class FlowService {
public readonly network: NetworkType;
private readonly flowJSON: object;
/**
* Initialize the Flow SDK
*/
constructor(flowJSON: object) {
this.network =
(import.meta.env.PUBLIC_FLOW_NETWORK as NetworkType) ?? "emulator";
this.flowJSON = flowJSON;
}
async onModuleInit() {
if (isGloballyInited) return;
const cfg = fcl.config();
// Required
await cfg.put("flow.network", this.network);
// Set the maximum of gas limit
await cfg.put("fcl.limit", 9999);
// Note: If you don't need to be compatible with an FCL-compatible wallet
// you don't need to configure these two parameters.
await cfg.put("app.detail.title", "App Title");
await cfg.put("app.detail.icon", "App Icon URL");
switch (this.network) {
case "mainnet":
// Required
await cfg.put(
"accessNode.api",
import.meta.env.PUBLIC_MAINNET_ENDPOINT ??
"https://mainnet.onflow.org"
);
// Note: If you don't need to be compatible with an FCL-compatible wallet
// you don't need to configure these two following parameters.
await cfg.put(
"discovery.wallet",
"https://fcl-discovery.onflow.org/authn"
);
await cfg.put(
"discovery.authn.endpoint",
"https://fcl-discovery.onflow.org/api/authn"
);
break;
case "testnet":
// Required
await cfg.put("accessNode.api", "https://testnet.onflow.org");
// Note: If you don't need to be compatible with an FCL-compatible wallet
// you don't need to configure these two following parameters.
await cfg.put(
"discovery.wallet",
"https://fcl-discovery.onflow.org/testnet/authn"
);
await cfg.put(
"discovery.authn.endpoint",
"https://fcl-discovery.onflow.org/api/testnet/authn"
);
break;
case "emulator":
// Required
await cfg.put("accessNode.api", "http://localhost:8888");
// Note: If you don't need to be compatible with an FCL-compatible wallet
// you don't need to configure these following parameters.
await cfg.put("discovery.wallet", "http://localhost:8701/fcl/authn");
break;
default:
throw new Error(`Unknown network: ${String(this.network)}`);
}
// Load Flow JSON
await cfg.load({ flowJSON: this.flowJSON });
isGloballyInited = true;
}
/**
* Ensure the Flow SDK is initialized
*/
private async ensureInited() {
if (isGloballyInited) return;
if (!globallyPromise) {
globallyPromise = this.onModuleInit();
}
return await globallyPromise;
}
/**
* Authenticate for current user
* Only supported on the front-end.
*/
async authenticate() {
await this.ensureInited();
fcl.authenticate();
}
/**
* Logout
* Only supported on the front-end.
*/
unauthenticate() {
fcl.unauthenticate();
}
/**
* Get the current logged-in
* Only supported on the front-end.
*/
get currentUser() {
return fcl.currentUser;
}
/**
* Get account information
*/
async getAccount(addr: string): Promise<Account> {
await this.ensureInited();
return await fcl.send([fcl.getAccount(addr)]).then(fcl.decode);
}
/**
* General method of sending transaction
*/
async sendTransaction(
code: string,
args: fcl.ArgumentFunction,
mainAuthz?: fcl.FclAuthorization,
extraAuthz?: fcl.FclAuthorization[]
) {
await this.ensureInited();
if (typeof mainAuthz !== "undefined") {
return await fcl.mutate({
cadence: code,
args: args,
proposer: mainAuthz,
payer: mainAuthz,
authorizations:
(extraAuthz?.length ?? 0) === 0
? [mainAuthz]
: [mainAuthz, ...extraAuthz],
});
} else {
return await fcl.mutate({
cadence: code,
args: args,
});
}
}
/**
* Get transaction status
*/
async getTransactionStatus(
transactionId: string
): Promise<TransactionStatus> {
await this.ensureInited();
return await fcl.tx(transactionId).onceExecuted();
}
/**
* Get chain id
*/
async getChainId() {
await this.ensureInited();
return await fcl.getChainId();
}
/**
* Send transaction with single authorization
*/
async onceTransactionSealed(
transactionId: string
): Promise<TransactionStatus> {
await this.ensureInited();
return fcl.tx(transactionId).onceSealed();
}
/**
* Get block object
* @param blockId
*/
async getBlockHeaderObject(blockId: string): Promise<fcl.BlockHeaderObject> {
await this.ensureInited();
return await fcl
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
.send([fcl.getBlockHeader(), fcl.atBlockId(blockId)])
.then(fcl.decode);
}
/**
* Send script
*/
async executeScript<T>(
code: string,
args: fcl.ArgumentFunction,
defaultValue: T
): Promise<T> {
await this.ensureInited();
try {
const queryResult = await fcl.query({
cadence: code,
args,
});
return (queryResult as T) ?? defaultValue;
} catch (e) {
console.error(e);
return defaultValue;
}
}
}
If you don't need to use an FCL-compatible wallet for on-chain interactions, you can use this Signer class:
In the following documentation, flow means an instence of flowSigner or flowService as the subject of function calls.
// FIXeS configure
import flowJSON from "@fixes/contracts/flow.json" assert { type: "json" };
// FIXeS Transactions
import txHeartbeatStaking from "@fixes/contracts/transactions/staking/heartbeat-staking.cdc?raw";
// FIXeS Scripts
import scResolveName from "@fixes/contracts/scripts/utils/resolve-name.cdc?raw";
import { FlowService } from "./flow.service";
import FlowSigner from "./Signer";
async function heartbeat(tickerName: string): Promise<string> {
const flowSigner = new FlowSigner(signerAddr, signerPrivKey, signerKeyId);
// If you want to directly use FCL-compatible wallets on the frontend,
// you can also use flowService here, but you need to connect the wallet
// first using flowService.authenticate
const txid = await flowSigner.sendTransaction(
txHeartbeatStaking,
(arg, t) => [arg(tickerName, t.String)]
);
return txid;
}
async function resolveAddressName(addr: string): Promise<string> {
const flowService = new FlowService(flowJSON);
return await flowService.executeScript(
scResolveName,
(arg, t) => [arg(addr, t.Address)]
addr
)
}