Skip to content

Commit

Permalink
feat/balances and proposal improvements (#159)
Browse files Browse the repository at this point in the history
* feat: watch balance makes API call to trigger backend sub to balance

* chore: version bump

* feat: better response handling from asset-watcher
  • Loading branch information
LukasDeco authored Jun 20, 2024
1 parent 51d4fc7 commit 92dcd37
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 35 deletions.
5 changes: 4 additions & 1 deletion lib/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,10 @@ export interface FutarchyBalancesClient {
passTokenUrl?: string,
failTokenUrl?: string
): Promise<TokenWithBalancePDAAndProposal[]>;
watchTokenBalance(tokenWithPDA: TokenWithPDA): Observable<TokenWithBalance>;
watchTokenBalance(
tokenWithPDA: TokenWithPDA,
authToken?: string
): Observable<TokenWithBalance>;
}

export interface FutarchyMarketsClient {
Expand Down
80 changes: 63 additions & 17 deletions lib/client/indexer/balances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
ProposalState
} from "@/types/proposals";
import { FutarchyRPCBalancesClient } from "../rpc";
import { Observable, catchError, of, switchMap } from "rxjs";
import { Observable, catchError, from, of, switchMap } from "rxjs";
import { Client as GQLWebSocketClient } from "graphql-ws";
import { Client as IndexerGraphQLClient } from "./__generated__";
import {
Expand All @@ -32,14 +32,17 @@ export class FutarchyIndexerBalancesClient implements FutarchyBalancesClient {
private rpcBalancesClient: FutarchyRPCBalancesClient;
private graphqlWSClient: GQLWebSocketClient;
private graphqlClient: IndexerGraphQLClient;
private balancesApiURL: string;
constructor(
rpcBalancesClient: FutarchyRPCBalancesClient,
graphqlWSClient: GQLWebSocketClient,
graphqlClient: IndexerGraphQLClient
graphqlClient: IndexerGraphQLClient,
balancesApiURL: string
) {
this.rpcBalancesClient = rpcBalancesClient;
this.graphqlWSClient = graphqlWSClient;
this.graphqlClient = graphqlClient;
this.balancesApiURL = balancesApiURL;
}

/**
Expand Down Expand Up @@ -230,25 +233,68 @@ export class FutarchyIndexerBalancesClient implements FutarchyBalancesClient {
return this.rpcBalancesClient.fetchTokenBalance(pda, token);
}

watchTokenBalance(tokenWithPDA: TokenWithPDA): Observable<TokenWithBalance> {
// how do we initially fetch from RPC and then
const indexerObservable = this.watchTokenAcctForArgs(
{
where: {
token_acct: { _eq: tokenWithPDA.pda.toBase58() }
watchTokenBalance(
tokenWithPDA: TokenWithPDA,
authToken: string
): Observable<TokenWithBalance> {
const url = `${this.balancesApiURL}/watch-token-balance`;

const postData = {
tokenAcct: tokenWithPDA.pda.toBase58()
};

const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${authToken}`
};

// Make the POST request using fetch and convert the promise to an observable
const apiCall$ = from(
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(postData)
}).then((response) => {
if (!response.ok) {
throw new Error(
"balances API (asset-watcher) returned an error for trying to watch this balance... " +
response.text() +
" " +
response.statusText
);
}
},
tokenWithPDA.token
return response.json();
})
);

return indexerObservable.pipe(
catchError((_) => {
const rpcObservable =
this.rpcBalancesClient.watchTokenBalance(tokenWithPDA);
return rpcObservable;
// Call the initial API to trigger watching on account
return apiCall$.pipe(
catchError((error) => {
console.error("Error triggering watch on account:", error);
// Fallback to RPC observable in case of an error
return this.rpcBalancesClient.watchTokenBalance(tokenWithPDA);
}),
switchMap((value) => {
return of(value);
switchMap(() => {
// After triggering the watch, fetch from RPC
const indexerObservable = this.watchTokenAcctForArgs(
{
where: {
token_acct: { _eq: tokenWithPDA.pda.toBase58() }
}
},
tokenWithPDA.token
);

return indexerObservable.pipe(
catchError((_) => {
const rpcObservable =
this.rpcBalancesClient.watchTokenBalance(tokenWithPDA);
return rpcObservable;
}),
switchMap((value) => {
return of(value);
})
);
})
);
}
Expand Down
16 changes: 12 additions & 4 deletions lib/client/indexer/indexerClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export class FutarchyIndexerClient implements FutarchyClient {
constructor(
rpcClient: FutarchyRPCClient,
indexerURL: string,
indexerWSURL: string
indexerWSURL: string,
balancesApiURL: string
) {
// TODO how can we batch these queries??
const options = {
Expand Down Expand Up @@ -58,7 +59,8 @@ export class FutarchyIndexerClient implements FutarchyClient {
this.balances = new FutarchyIndexerBalancesClient(
rpcClient.balances,
this.wsClient,
graphqlClient
graphqlClient,
balancesApiURL
);
this.markets = new FutarchyIndexerMarketsClient(
rpcClient.markets.openbook,
Expand Down Expand Up @@ -110,8 +112,14 @@ export class FutarchyIndexerClient implements FutarchyClient {
static make(
rpcClient: FutarchyRPCClient,
indexerURL: string,
indexerWSURL: string
indexerWSURL: string,
balancesApiURL: string
) {
return new FutarchyIndexerClient(rpcClient, indexerURL, indexerWSURL);
return new FutarchyIndexerClient(
rpcClient,
indexerURL,
indexerWSURL,
balancesApiURL
);
}
}
29 changes: 17 additions & 12 deletions lib/client/rpc/dao.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { enrichTokenMetadata } from "@/tokens";
import { PublicKey } from "@solana/web3.js";
import { createSlug } from "@/utils";
import { Autocrat, IDL as AUTOCRAT_V0_3_IDL } from "@/idl/autocrat_v0.3";
import { AUTOCRAT_PROGRAM_ID } from "@metadaoproject/futarchy";

export class FutarchyRPCDaoClient implements FutarchyDaoClient {
private futarchyProtocols: FutarchyProtocol[];
Expand Down Expand Up @@ -138,7 +139,7 @@ export class FutarchyRPCDaoClient implements FutarchyDaoClient {
): Promise<{ base: BN; quote: BN } | undefined> {
const autocrat = new Program<Autocrat>(
AUTOCRAT_V0_3_IDL,
"autoQP9RmUNkzzKRXsMkWicDVZ3h29vvyMDcAYjCxxg ",
AUTOCRAT_PROGRAM_ID,
this.rpcProvider
);
const currentDao = daoAggregate.daos
Expand Down Expand Up @@ -173,17 +174,21 @@ export class FutarchyRPCDaoClient implements FutarchyDaoClient {
);

const tokens = await Promise.all(
tokenAccounts.value.map(async (accountInfo) => {
const tokenAmount = accountInfo.account.data.parsed.info.tokenAmount;
const token = await enrichTokenMetadata(
accountInfo.account.data.parsed.info.mint,
this.rpcProvider
);
return {
token: token,
balance: tokenAmount.uiAmount
};
})
tokenAccounts.value
.filter((accountInfo) =>
PublicKey.isOnCurve(accountInfo.account.data.parsed.info.mint)
)
.map(async (accountInfo) => {
const tokenAmount = accountInfo.account.data.parsed.info.tokenAmount;
const token = await enrichTokenMetadata(
new PublicKey(accountInfo.account.data.parsed.info.mint),
this.rpcProvider
);
return {
token: token,
balance: tokenAmount.uiAmount
};
})
);

return {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@metadaoproject/futarchy-sdk",
"version": "3.0.0-alpha.15",
"version": "3.0.0-alpha.16",
"main": "dist",
"scripts": {
"preinstall": "npx only-allow pnpm",
Expand Down

0 comments on commit 92dcd37

Please sign in to comment.