Skip to content

Commit

Permalink
added: more chains, better error handling, bum to 0.0.7
Browse files Browse the repository at this point in the history
added: more chains, better error handling, bum to 0.0.7
Throw an error if the chain is not supported instead of using default chain.
  • Loading branch information
Salmandabbakuti committed Sep 28, 2023
1 parent 046a7b0 commit d2d5752
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 81 deletions.
47 changes: 43 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# SuperJWT

![npm version](https://img.shields.io/badge/npm-0.0.7-brightgreen)

Super-JWT is a Node.js package that helps authenticate users based on Superfluid streams using JSON Web Tokens (JWT).

#### Installation
Expand All @@ -26,13 +28,13 @@ To authenticate a user with a Superfluid stream, use the `authenticateWithStream

An object that represents the required parameters for authenticating a Superfluid stream. It has the following properties:

`chain`: A Chain value that represents the Ethereum chain on which the Superfluid stream is created.
`chain`: A Chain value that represents the chain on which the Superfluid stream is created. See [supported chains](#supported-chains) for more information.

`sender`: A string that represents the Ethereum address of the sender of the stream.
`sender`: A string that represents the ethereum address of the sender of the stream.

`receiver`: A string that represents the Ethereum address of the receiver of the stream.
`receiver`: A string that represents the ethereum address of the receiver of the stream.

`token`: A string that represents the address of the ERC20 token used in the Superfluid stream. It can be the address of the underlying SuperToken.
`token`: A string that represents the ethereum address of the SuperToken being used.

In addition to the required parameters mentioned earlier, you can also pass any of the `where` parameters of the Superfluid subgraph `streams` query. This allows you to filter streams based on other properties such as `currentFlowRate_gt`, which is the flow rate in the stream. For more information on the available query parameters, you can refer to the [Superfluid subgraph documentation](https://thegraph.com/hosted-service/subgraph/superfluid-finance/protocol-v1-goerli).

Expand Down Expand Up @@ -91,6 +93,43 @@ console.log(decoded);
// }
```

#### Supported Chains

Super-JWT supports the following chains:

```ts
type Chain =
| "goerli"
| "mumbai"
| "matic"
| "mainnet"
| "opgoerli"
| "arbgoerli"
| "fuji"
| "xdai"
| "optimism"
| "avalanche"
| "bsc"
| "celo"
| "base";
```

### Publishing

To publish a new version of the package to npm, run the following command:

```shell
npm run publish
```

### Change Log

#### 0.0.7

- Added more chains to the supported chains list. see [supported chains](#supported-chains) for more information.
- Throw an error if the chain is not supported instead of using default chain.
- Better error handling.

### Safety

This is experimental software and subject to change over time.
Expand Down
23 changes: 11 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "super-jwt",
"version": "0.0.6",
"version": "0.0.7",
"description": "Super-JWT helps to authenticate your users based on Superfluid streams using JSON Web Tokens (JWT)",
"author": "Salman Dabbakuti",
"license": "MIT",
Expand All @@ -16,22 +16,21 @@
"superfluid-auth"
],
"dependencies": {
"graphql": "^16.6.0",
"graphql-request": "^5.2.0",
"jsonwebtoken": "^9.0.0"
"graphql": "^16.8.1",
"graphql-request": "^6.1.0",
"jsonwebtoken": "^9.0.2"
},
"devDependencies": {
"@types/chai": "^4.3.4",
"@types/chai-as-promised": "^7.1.5",
"@types/jsonwebtoken": "^9.0.1",
"@types/mocha": "^10.0.1",
"chai": "^4.3.7",
"@types/chai": "^4.3.6",
"@types/chai-as-promised": "^7.1.6",
"@types/jsonwebtoken": "^9.0.3",
"@types/mocha": "^10.0.2",
"chai": "^4.3.10",
"chai-as-promised": "^7.1.1",
"mocha": "^10.2.0",
"super-jwt": "^0.0.2",
"ts-node": "^10.9.1",
"tslib": "^2.5.0",
"typescript": "^5.0.3"
"tslib": "^2.6.2",
"typescript": "^5.2.2"
},
"repository": {
"type": "git",
Expand Down
115 changes: 84 additions & 31 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
import { request, gql } from "graphql-request";
import jwt, { JwtPayload, SignOptions, Secret } from "jsonwebtoken";

export type Chain = "goerli" | "mumbai" | "matic";
export type Chain =
| "goerli"
| "mumbai"
| "matic"
| "mainnet"
| "opgoerli"
| "arbgoerli"
| "fuji"
| "xdai"
| "optimism"
| "avalanche"
| "bsc"
| "celo"
| "base";

interface Stream {
id: string;
Expand All @@ -12,57 +25,97 @@ interface StreamQueryResult {
}

export interface StreamPayload {
chain: Chain | string;
chain: Chain;
sender: string;
receiver: string;
token: string;
[key: string]: any;
}

export interface AuthenticationResult {
token: string;
stream: StreamPayload | JwtPayload;
}

const defaultSubgraphUrls: Record<Chain | string, string> = {
const defaultSubgraphUrls: Record<Chain, string> = {
goerli:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-goerli",
mumbai:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-mumbai",
matic:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-matic"
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-matic",
mainnet:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-eth-mainnet",
opgoerli:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-optimism-goerli",
arbgoerli:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-arbitrum-goerli",
fuji: "https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-avalanche-fuji",
xdai: "https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-xdai",
optimism:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-optimism-mainnet",
avalanche:
"https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-avalanche-c",
bsc: "https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-bsc-mainnet",
celo: "https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-celo-mainnet",
base: "https://api.thegraph.com/subgraphs/name/superfluid-finance/protocol-v1-base"
};

const STREAMS_QUERY = gql`
query GetStreams($first: Int, $where: Stream_filter) {
streams(first: $first, where: $where) {
id
}
}
`;

// Retrieve streams using the Superfluid subgraph
const getStreams = async ({
async function getStreams({
chain,
...streamWhereParams
}: StreamPayload): Promise<Stream[]> => {
const STREAMS_QUERY = gql`
query GetStreams($first: Int, $where: Stream_filter) {
streams(first: $first, where: $where) {
id
}
}
`;
const subgraphUrl =
defaultSubgraphUrls[chain] || defaultSubgraphUrls["goerli"];
const { streams }: StreamQueryResult = await request(
subgraphUrl,
STREAMS_QUERY,
{
first: 1,
where: {
...streamWhereParams
}: StreamPayload): Promise<Stream[]> {
const subgraphUrl = defaultSubgraphUrls[chain];
if (!subgraphUrl)
throw new Error(`super-jwt: Chain ${chain} is not supported`);
try {
const { streams }: StreamQueryResult = await request(
subgraphUrl,
STREAMS_QUERY,
{
first: 1,
where: {
...streamWhereParams
}
}
}
);
return streams;
};
);
return streams;
} catch (err) {
console.warn(`super-jwt: Failed to retrieve streams: ${err}`);
return [];
}
}

export async function authenticateWithStream(
streamPayload: StreamPayload,
secret: Secret,
jwtOptions: SignOptions
): Promise<AuthenticationResult> {
const requiredParams = ["chain", "sender", "receiver", "token"];

if (!requiredParams.every((param) => param in streamPayload)) {
throw new Error(
"super-jwt: Missing required stream payload params: chain, sender, receiver, token"
);
}

export async function authenticateWithStream(streamPayload: StreamPayload, secret: Secret, jwtOptions: SignOptions): Promise<AuthenticationResult> {
if (!["chain", "sender", "receiver", "token"].every((param) => streamPayload.hasOwnProperty(param))) throw new Error("super-jwt: Missing required stream payload params: chain, sender, receiver, token");
const streams = await getStreams(streamPayload);
if (!streams || streams.length === 0) throw new Error("super-jwt: No stream found to authenticate between sender and receiver");

if (!streams || streams.length === 0) {
throw new Error(
"super-jwt: No stream found to authenticate between sender and receiver"
);
}

const jwtToken = jwt.sign(streamPayload, secret, jwtOptions);
return { token: jwtToken, stream: streamPayload };
}
Expand All @@ -71,7 +124,7 @@ export function verifyToken(jwtToken: string, secret: Secret): JwtPayload {
try {
const decoded = jwt.verify(jwtToken, secret) as JwtPayload;
return decoded;
} catch (err: unknown) {
} catch (err) {
throw new Error(`super-jwt: failed to verify token: ${err}`);
}
}
}
Loading

0 comments on commit d2d5752

Please sign in to comment.