Skip to content

Commit ecf966f

Browse files
authored
Add fees retrieval (#114)
* add fees retrieval * rename fields for consistency
1 parent c28cc07 commit ecf966f

16 files changed

+266
-5
lines changed

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22
"packages": [
33
"packages/*"
44
],
5-
"version": "5.7.1",
5+
"version": "5.8.0",
66
"$schema": "node_modules/lerna/schemas/lerna-schema.json"
77
}

package-lock.json

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/stream/aptos/StreamClient.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import {
88
ICreateMultipleStreamData,
99
ICreateResult,
1010
ICreateStreamData,
11+
IGetFeesData,
1112
IGetOneData,
13+
IFees,
1214
IMultiTransactionResult,
1315
IRecipient,
1416
ITopUpData,
@@ -18,7 +20,14 @@ import {
1820
IWithdrawData,
1921
} from "../common/types";
2022
import { APTOS_PROGRAM_IDS } from "./constants";
21-
import { Contract, ICreateStreamAptosExt, ITransactionAptosExt, StreamResource } from "./types";
23+
import {
24+
ConfigResource,
25+
Contract,
26+
FeeTableResource,
27+
ICreateStreamAptosExt,
28+
ITransactionAptosExt,
29+
StreamResource,
30+
} from "./types";
2231
import { AptosWalletWrapper } from "./wallet";
2332
import { extractAptosErrorCode } from "./utils";
2433

@@ -237,6 +246,31 @@ export default class AptosStreamClient extends BaseStreamClient {
237246
return { ixs: [payload], txId: hash };
238247
}
239248

249+
public async getFees({ address }: IGetFeesData): Promise<IFees | null> {
250+
const resource = await this.client.getAccountResource(
251+
this.programId,
252+
`${this.programId}::fees::FeeTable`
253+
);
254+
const data = resource.data as unknown as FeeTableResource;
255+
const value = await this.client.getTableItem(data.values.handle, {
256+
key_type: "address",
257+
key: address,
258+
value_type: "u64",
259+
});
260+
if (!value) {
261+
return null;
262+
}
263+
return { streamflowFee: Number(value) / 100, partnerFee: 0 };
264+
}
265+
266+
public async getDefaultStreamflowFee(): Promise<number> {
267+
const resource = await this.client.getAccountResource(
268+
this.programId,
269+
`${this.programId}::admin::ConfigV2`
270+
);
271+
return Number((resource.data as unknown as ConfigResource).streamflow_fees) / 100;
272+
}
273+
240274
public extractErrorCode(err: Error): string | null {
241275
return extractAptosErrorCode(err.toString() ?? "Unknown error!");
242276
}

packages/stream/aptos/types.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ export interface StreamResource {
5454
withdrawn: string;
5555
}
5656

57+
export interface FeeTableResource {
58+
values: {
59+
handle: string;
60+
};
61+
}
62+
63+
export interface ConfigResource {
64+
admin: string;
65+
streamflow_fees: string;
66+
treasury: string;
67+
tx_fee: string;
68+
withdrawor: string;
69+
}
70+
5771
export class Contract implements Stream {
5872
magic: number;
5973

packages/stream/common/BaseStreamClient.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import {
22
ICreateStreamData,
33
ICreateMultipleStreamData,
4+
IFees,
45
IWithdrawData,
56
ICancelData,
67
ITransferData,
78
ITopUpData,
9+
IGetFeesData,
810
IGetOneData,
911
IUpdateData,
1012
ITransactionResult,
@@ -42,6 +44,10 @@ export abstract class BaseStreamClient {
4244

4345
abstract update(updateData: IUpdateData, chainSpecificParams: any): Promise<ITransactionResult>;
4446

47+
abstract getFees(getFeesData: IGetFeesData, chainSpecificParams: any): Promise<IFees | null>;
48+
49+
abstract getDefaultStreamflowFee(chainSpecificParams: any): Promise<number>;
50+
4551
// eslint-disable-next-line @typescript-eslint/no-unused-vars
4652
extractErrorCode(err: Error): string | null {
4753
return null;

packages/stream/common/GenericStreamClient.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import {
1818
ICreateResult,
1919
IGetAllData,
2020
Stream,
21+
IFees,
22+
IGetFeesData,
2123
} from "./types";
2224
import { handleContractError } from "./utils";
2325
import { AptosStreamClient, ICreateStreamAptosExt, ITransactionAptosExt } from "../aptos";
@@ -262,4 +264,18 @@ export default class GenericStreamClient<T extends IChain> extends BaseStreamCli
262264
this.nativeStreamClient.extractErrorCode
263265
);
264266
}
267+
268+
/**
269+
* Returns streamflow and partner fees for the specific wallet in %
270+
*/
271+
public getFees(getFeesData: IGetFeesData): Promise<IFees | null> {
272+
return this.nativeStreamClient.getFees(getFeesData);
273+
}
274+
275+
/**
276+
* Returns default Streamflow Fee in %
277+
*/
278+
public getDefaultStreamflowFee(): Promise<number> {
279+
return this.nativeStreamClient.getDefaultStreamflowFee();
280+
}
265281
}

packages/stream/common/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ export interface IGetOneData {
6464
id: string;
6565
}
6666

67+
export interface IGetFeesData {
68+
address: string;
69+
}
70+
6771
export interface IGetAllData {
6872
address: string;
6973
type?: StreamType;
@@ -83,6 +87,11 @@ export interface ITransactionResult {
8387
txId: string;
8488
}
8589

90+
export interface IFees {
91+
streamflowFee: number;
92+
partnerFee: number;
93+
}
94+
8695
export interface ICreateResult extends ITransactionResult {
8796
metadataId: MetadataId;
8897
}

packages/stream/evm/StreamClient.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import {
1010
ICreateMultipleStreamData,
1111
ICreateResult,
1212
ICreateStreamData,
13+
IGetFeesData,
1314
IGetAllData,
1415
IGetOneData,
16+
IFees,
1517
IMultiTransactionResult,
1618
IRecipient,
1719
ITopUpData,
@@ -26,7 +28,7 @@ import { BNB_PROGRAM_IDS, ETHEREUM_PROGRAM_IDS, POLYGON_PROGRAM_IDS } from "./co
2628
import abi from "./abi";
2729
import ercAbi from "./ercAbi";
2830
import { BASE_FEE } from "../common/constants";
29-
import { EvmContract, StreamAbiResult } from "./types";
31+
import { EvmContract, FeesAbiResult, StreamAbiResult } from "./types";
3032
import { extractEvmErrorCode } from "./utils";
3133

3234
export default class EvmStreamClient extends BaseStreamClient {
@@ -251,6 +253,22 @@ export default class EvmStreamClient extends BaseStreamClient {
251253
return extractEvmErrorCode(err.toString() ?? "Unknown error!");
252254
}
253255

256+
public async getFees({ address }: IGetFeesData): Promise<IFees | null> {
257+
const fees: FeesAbiResult = await this.readContract.getFees(address);
258+
if (!fees.exists) {
259+
return null;
260+
}
261+
return {
262+
streamflowFee: fees.streamflow_fee.toNumber() / 100,
263+
partnerFee: fees.partner_fee.toNumber() / 100,
264+
};
265+
}
266+
267+
public async getDefaultStreamflowFee(): Promise<number> {
268+
const fee = await this.readContract.getStreamflowFees();
269+
return fee.toNumber() / 100;
270+
}
271+
254272
/**
255273
* Returns StreamClient protocol program ID.
256274
*/

packages/stream/evm/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ export interface StreamAbiResult {
4848
withdrawn: BigNumber;
4949
}
5050

51+
export interface FeesAbiResult {
52+
exists: boolean;
53+
streamflow_fee: BigNumber;
54+
partner_fee: BigNumber;
55+
}
56+
5157
export class EvmContract implements Stream {
5258
magic: number;
5359

packages/stream/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@streamflow/stream",
3-
"version": "5.7.1",
3+
"version": "5.8.0",
44
"description": "JavaScript SDK to interact with Streamflow protocol.",
55
"main": "dist/index.js",
66
"homepage": "https://github.com/streamflow-finance/js-sdk/",
@@ -38,6 +38,7 @@
3838
"@suiet/wallet-kit": "0.2.18",
3939
"aptos": "1.4.0",
4040
"bn.js": "5.2.1",
41+
"borsh": "^2.0.0",
4142
"bs58": "5.0.0",
4243
"ethereum-checksum-address": "0.0.8",
4344
"ethers": "5.7.2",

packages/stream/solana/StreamClient.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
sendAndConfirmRawTransaction,
1818
BlockheightBasedTransactionConfirmationStrategy,
1919
} from "@solana/web3.js";
20+
import * as borsh from "borsh";
2021

2122
import {
2223
Account,
@@ -46,6 +47,10 @@ import {
4647
TX_FINALITY_CONFIRMED,
4748
WITHDRAWOR_PUBLIC_KEY,
4849
FEE_ORACLE_PUBLIC_KEY,
50+
DEFAULT_STREAMFLOW_FEE,
51+
PARTNER_ORACLE_PROGRAM_ID,
52+
FEES_METADATA_SEED,
53+
PARTNERS_SCHEMA,
4954
} from "./constants";
5055
import {
5156
withdrawStreamInstruction,
@@ -64,7 +69,9 @@ import {
6469
ICreateResult,
6570
ICreateStreamData,
6671
IGetAllData,
72+
IGetFeesData,
6773
IGetOneData,
74+
IFees,
6875
IMultiTransactionResult,
6976
IRecipient,
7077
IStreamConfig,
@@ -79,6 +86,7 @@ import {
7986
ICreateMultiError,
8087
} from "../common/types";
8188
import { BaseStreamClient } from "../common/BaseStreamClient";
89+
import { IPartnerLayout } from "./instructionTypes";
8290

8391
const METADATA_ACC_SIZE = 1104;
8492

@@ -801,6 +809,32 @@ export default class SolanaStreamClient extends BaseStreamClient {
801809
};
802810
}
803811

812+
public async getFees({ address }: IGetFeesData): Promise<IFees | null> {
813+
const [metadataPubKey] = PublicKey.findProgramAddressSync(
814+
[Buffer.from(FEES_METADATA_SEED)],
815+
new PublicKey(PARTNER_ORACLE_PROGRAM_ID)
816+
);
817+
const data = await this.connection.getAccountInfo(metadataPubKey);
818+
if (!data) {
819+
return null;
820+
}
821+
const partners = borsh.deserialize(PARTNERS_SCHEMA, data!.data) as unknown as IPartnerLayout[];
822+
const filteredPartners = partners.filter(
823+
(item) => new PublicKey(item.pubkey).toString() === address
824+
);
825+
if (filteredPartners.length === 0) {
826+
return null;
827+
}
828+
return {
829+
streamflowFee: Number(filteredPartners[0].strm_fee.toFixed(4)),
830+
partnerFee: Number(filteredPartners[0].partner_fee.toFixed(4)),
831+
};
832+
}
833+
834+
public async getDefaultStreamflowFee(): Promise<number> {
835+
return DEFAULT_STREAMFLOW_FEE;
836+
}
837+
804838
public extractErrorCode(err: Error): string | null {
805839
return extractSolanaErrorCode(err.toString() ?? "Unknown error!");
806840
}

packages/stream/solana/constants.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ export const STREAMFLOW_PROGRAM_ID = "strmRqUCoQUgGUan5YhzUZa6KqdzwX5L6FpUxfmKg5
2121

2222
export const STREAMFLOW_DEVNET_PROGRAM_ID = "FGjLaVo5zLGdzCxMo9gu9tXr1kzTToKd8C8K7YS5hNM1";
2323

24+
export const PARTNER_ORACLE_PROGRAM_ID = "pardpVtPjC8nLj1Dwncew62mUzfChdCX1EaoZe8oCAa";
25+
2426
export const STREAMFLOW_TREASURY_PUBLIC_KEY = new PublicKey(
2527
"5SEpbdjFK5FxwTvfsGMXVQTD2v4M2c5tyRTxhdsPkgDw"
2628
);
@@ -31,8 +33,17 @@ export const FEE_ORACLE_PUBLIC_KEY = new PublicKey("B743wFVk2pCYhV91cn287e1xY7f1
3133

3234
export const AIRDROP_TEST_TOKEN = "Gssm3vfi8s65R31SBdmQRq6cKeYojGgup7whkw4VCiQj";
3335

36+
export const FEES_METADATA_SEED = Buffer.from("strm_fees");
37+
38+
export const DEFAULT_STREAMFLOW_FEE = 0.99;
39+
3440
export const AIRDROP_AMOUNT = 1; // 1 SOL is the cap on the testnet
3541

42+
export const PARTNER_SCHEMA = {
43+
struct: { pubkey: { array: { type: "u8", len: 32 } }, partner_fee: "f32", strm_fee: "f32" },
44+
};
45+
export const PARTNERS_SCHEMA = { array: { type: PARTNER_SCHEMA } };
46+
3647
export const SOLANA_ERROR_MATCH_REGEX = /custom program error: (0x\d{2})/;
3748

3849
export const SOLANA_ERROR_MAP: { [key: number]: string } = {

packages/stream/solana/instructionTypes.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,9 @@ export interface IUpdateStreamLayout {
9999
export interface ITopupStreamLayout {
100100
amount: Uint8Array;
101101
}
102+
103+
export interface IPartnerLayout {
104+
pubkey: Uint8Array;
105+
partner_fee: number;
106+
strm_fee: number;
107+
}

packages/stream/solana/layout.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { CREATE_PARAMS_PADDING } from "./constants";
44
import {
55
ICreateStreamLayout,
66
ICreateUncheckedStreamLayout,
7+
IPartnerLayout,
78
IStreamLayout,
89
ITopupStreamLayout,
910
IUpdateStreamLayout,
@@ -66,6 +67,12 @@ export const streamLayout: BufferLayout.Structure<IStreamLayout> = BufferLayout.
6667
BufferLayout.blob(8, "funds_unlocked_at_last_rate_change"),
6768
]);
6869

70+
export const partnerLayout: BufferLayout.Structure<IPartnerLayout> = BufferLayout.struct([
71+
BufferLayout.blob(32, "pubkey"),
72+
BufferLayout.f32("partner_fee"),
73+
BufferLayout.f32("strm_fee"),
74+
]);
75+
6976
/**
7077
* Create stream instruction layout
7178
*/

0 commit comments

Comments
 (0)