Skip to content

Commit

Permalink
Featured Osmosis Enhanced Starter (#57)
Browse files Browse the repository at this point in the history
* Featured Osmosis Enhanced Starter

* Update example Osmosis project

---------

Co-authored-by: James Bayly <[email protected]>
  • Loading branch information
bgodlin and jamesbayly authored Dec 8, 2023
1 parent 518eb48 commit 8ef5fc2
Show file tree
Hide file tree
Showing 5 changed files with 157 additions and 45 deletions.
4 changes: 2 additions & 2 deletions Osmosis/osmosis-starter/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ services:
- ${SUB_COMMAND:-} # set SUB_COMMAND env variable to "test" to run tests
- -f=/app
- --db-schema=app
- --workers=4
- --batch-size=30
- --workers=1
- --batch-size=2
- --unfinalized-blocks=true
healthcheck:
test: ["CMD", "curl", "-f", "http://subquery-node:3000/ready"]
Expand Down
2 changes: 1 addition & 1 deletion Osmosis/osmosis-starter/package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Osmosis",
"name": "osmosis-starter",
"version": "0.0.1",
"description": "This project can be use as a starting point for developing your Cosmos (Osmosis) based SubQuery project. This Cosmos Example Project indexes all swaps on Osmosis' on chain DEX",
"main": "dist/index.js",
Expand Down
32 changes: 24 additions & 8 deletions Osmosis/osmosis-starter/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const project: CosmosProject = {
version: "0.0.1",
name: "osmosis-starter",
description:
"This project can be use as a starting point for developing your Cosmos osmosis based SubQuery project",
"This project can be use as a starting point for developing your Cosmos Osmosis based SubQuery project. It indexes all swaps in the Osmosis DEX",
runner: {
node: {
name: "@subql/node-cosmos",
Expand All @@ -35,27 +35,29 @@ const project: CosmosProject = {
* If you use a rate limited endpoint, adjust the --batch-size and --workers parameters
* These settings can be found in your docker-compose.yaml, they will slow indexing but prevent your project being rate limited
*/
endpoint: ["https://osmosis.api.onfinality.io/public"],
endpoint: ["https://rpc.osmosis.zone:443"],
chaintypes: new Map([
[
"osmosis.gamm.v1beta1",
{
file: "./proto/osmosis/gamm/v1beta1/tx.proto",
messages: ["MsgSwapExactAmountIn"],
messages: [
"MsgSwapExactAmountIn",
"MsgSwapExactAmountOut",
"MsgJoinSwapShareAmountOut",
],
},
],
[
" osmosis.poolmanager.v1beta1",
{
// needed by MsgSwapExactAmountIn
file: "./proto/osmosis/poolmanager/v1beta1/swap_route.proto",
messages: ["SwapAmountInRoute"],
messages: ["SwapAmountOutRoute", "SwapAmountInRoute"],
},
],
[
"cosmos.base.v1beta1",
{
// needed by MsgSwapExactAmountIn
file: "./proto/cosmos/base/v1beta1/coin.proto",
messages: ["Coin"],
},
Expand All @@ -65,17 +67,31 @@ const project: CosmosProject = {
dataSources: [
{
kind: CosmosDatasourceKind.Runtime,
startBlock: 9798050,
startBlock: 12678493,
mapping: {
file: "./dist/index.js",
handlers: [
{
handler: "handleMessage",
handler: "handleMsgSwapExactAmountIn",
kind: CosmosHandlerKind.Message,
filter: {
type: "/osmosis.gamm.v1beta1.MsgSwapExactAmountIn",
},
},
{
handler: "handleMsgSwapExactAmountOut",
kind: CosmosHandlerKind.Message,
filter: {
type: "/osmosis.gamm.v1beta1.MsgSwapExactAmountOut",
},
},
{
handler: "handleMsgJoinSwapShareAmountOut",
kind: CosmosHandlerKind.Message,
filter: {
type: "/osmosis.gamm.v1beta1.MsgJoinSwapShareAmountOut",
},
},
],
},
},
Expand Down
30 changes: 19 additions & 11 deletions Osmosis/osmosis-starter/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@
# Add the `@index` or `@index(unique: true)` annotation after any non-key field
# https://academy.subquery.network/build/graphql.html#indexing-by-non-primary-key-field

# type Block @entity {
# id: ID! # The block hash
# height: BigInt!
# }
enum Direction {
IN
OUT
}

# type Transaction @entity {
# id: ID!
# blockHeight: BigInt!
# timestamp: String!
# }
enum Message {
MsgSwapExactAmountIn
MsgSwapExactAmountOut
MsgJoinSwapShareAmountOut
}

type Swap @entity {
id: ID!
sender: String!
direction: Direction!
txHash: String!
blockHeight: BigInt!
date: Date!
message: Message!
tokenInDenom: String
tokenInAmount: BigInt
tokenOutMin: BigInt!
tokenOutMin: BigInt
tokenOutDenom: String
tokenOutAmount: BigInt
tokenInMax: BigInt
swapRoutes: [SwapRoute] @derivedFrom(field: "swap") #This is virtual field
}

Expand All @@ -29,10 +35,12 @@ type SwapRoute @entity {
pool: Pool!
swap: Swap!
tokenInDenom: String
tokenOutDenom: String!
tokenOutDenom: String
}

type Pool @entity {
id: ID!
createdBlockHeight: BigInt!
created: Date!
swapRoutes: [SwapRoute] @derivedFrom(field: "pool") #This is virtual field
}
134 changes: 111 additions & 23 deletions Osmosis/osmosis-starter/src/mappings/mappingHandlers.ts
Original file line number Diff line number Diff line change
@@ -1,54 +1,142 @@
import { MsgSwapExactAmountInMessage } from "../types/CosmosMessageTypes";
import { Pool, Swap, SwapRoute } from "../types";
import {
MsgSwapExactAmountInMessage,
MsgSwapExactAmountOutMessage,
MsgJoinSwapShareAmountOutMessage,
} from "../types/CosmosMessageTypes";
import { Pool, Swap, SwapRoute, Direction, Message } from "../types";
import { CosmosBlock } from "@subql/types-cosmos";

async function checkGetPool(id: string): Promise<Pool> {
async function checkGetPool(id: string, block: CosmosBlock): Promise<Pool> {
// Check that the pool exists and create new ones if now
let pool = await Pool.get(id);
if (!pool) {
pool = new Pool(id);
pool = Pool.create({
id,
createdBlockHeight: BigInt(block.header.height),
created: new Date(block.header.time.toISOString()),
});
await pool.save();
}
return pool;
}

export async function handleMessage(
msg: MsgSwapExactAmountInMessage
): Promise<void> {
// You can see an example record here https://www.mintscan.io/osmosis/txs/6A22C6C978A96D99FCB08826807C6EB1DCBDCEC6044C35105B624A81A1CB6E24?height=9798771
logger.info(`New Swap Message received at block ${msg.block.header.height}`);
// logger.info(JSON.stringify(msg.tx.tx.events)); // You can use this to preview the data

// We first create a new swap record
const swap = Swap.create({
function createSwap(
msg:
| MsgSwapExactAmountInMessage
| MsgSwapExactAmountOutMessage
| MsgJoinSwapShareAmountOutMessage,
direction: Direction,
message: Message
): Swap {
return Swap.create({
id: `${msg.tx.hash}-${msg.idx}`,
txHash: msg.tx.hash,
blockHeight: BigInt(msg.block.block.header.height),
blockHeight: BigInt(msg.block.header.height),
sender: msg.msg.decodedMsg.sender,
tokenInDenom: msg.msg.decodedMsg.tokenIn?.denom,
tokenInAmount: msg.msg.decodedMsg.tokenIn
? BigInt(msg.msg.decodedMsg.tokenIn.amount)
: undefined,
tokenOutMin: BigInt(msg.msg.decodedMsg.tokenOutMinAmount),
direction,
message,
date: new Date(msg.block.header.time.toISOString()),
});
}

export async function handleMsgSwapExactAmountIn(
msg: MsgSwapExactAmountInMessage
): Promise<void> {
logger.info(
`Processing MsgSwapExactAmountIn at block ${msg.block.header.height.toString()}`
);
// We first create a new swap record
const swap = createSwap(msg, Direction.IN, Message.MsgSwapExactAmountIn);
swap.tokenInDenom = msg.msg.decodedMsg.tokenIn?.denom;
swap.tokenInAmount = msg.msg.decodedMsg.tokenIn
? BigInt(msg.msg.decodedMsg.tokenIn.amount)
: undefined;
swap.tokenOutMin = BigInt(msg.msg.decodedMsg.tokenOutMinAmount);

// Save this to the DB
await swap.save();

// Create swap routes from the array on the message
let lastTokenOutDenom = swap.tokenInDenom;
let currentTokenInDenom = swap.tokenInDenom;
for (const route of msg.msg.decodedMsg.routes) {
const index = msg.msg.decodedMsg.routes.indexOf(route);
// Check that the pool aready exists
const pool = await checkGetPool(route.poolId.toString());
const pool = await checkGetPool(route.poolId.toString(), msg.block);

const swapRoute = SwapRoute.create({
id: `${msg.tx.hash}-${msg.idx}-${index}`,
poolId: pool.id,
swapId: swap.id,
tokenInDenom: lastTokenOutDenom,
tokenInDenom: currentTokenInDenom,
tokenOutDenom: route.tokenOutDenom,
});
lastTokenOutDenom = route.tokenOutDenom;
currentTokenInDenom = route.tokenOutDenom;
await swapRoute.save();
}
}

export async function handleMsgSwapExactAmountOut(
msg: MsgSwapExactAmountOutMessage
): Promise<void> {
logger.info(
`Processing MsgSwapExactAmountOut at block ${msg.block.header.height.toString()}`
);
// We first create a new swap record
const swap = createSwap(msg, Direction.OUT, Message.MsgSwapExactAmountOut);
swap.tokenOutDenom = msg.msg.decodedMsg.tokenOut.denom;
swap.tokenOutAmount = msg.msg.decodedMsg.tokenOut
? BigInt(msg.msg.decodedMsg.tokenOut.amount)
: undefined;
swap.tokenInMax = BigInt(msg.msg.decodedMsg.tokenInMaxAmount);

// Save this to the DB
await swap.save();

// Create swap routes from the array on the message
let currentTokenOutDenom = swap.tokenOutDenom;
for (const route of msg.msg.decodedMsg.routes) {
const index = msg.msg.decodedMsg.routes.indexOf(route);
// Check that the pool aready exists
const pool = await checkGetPool(route.poolId.toString(), msg.block);

const swapRoute = SwapRoute.create({
id: `${msg.tx.hash}-${msg.idx}-${index}`,
poolId: pool.id,
swapId: swap.id,
tokenInDenom: route.tokenInDenom,
tokenOutDenom: currentTokenOutDenom,
});
currentTokenOutDenom = route.tokenInDenom;
await swapRoute.save();
}
}

export async function handleMsgJoinSwapShareAmountOut(
msg: MsgJoinSwapShareAmountOutMessage
): Promise<void> {
logger.info(
`Processing MsgJoinSwapShareAmountOut at block ${msg.block.header.height.toString()}`
);
// We first create a new swap record
const swap = createSwap(msg, Direction.IN, Message.MsgJoinSwapShareAmountOut);
swap.tokenInDenom = msg.msg.decodedMsg.tokenInDenom;
swap.tokenInMax = BigInt(msg.msg.decodedMsg.tokenInMaxAmount);
swap.tokenOutAmount = BigInt(msg.msg.decodedMsg.shareOutAmount);

// Save this to the DB
await swap.save();

// Create swap routes from the array on the message
const pool = await checkGetPool(
msg.msg.decodedMsg.poolId.toString(),
msg.block
);

const swapRoute = SwapRoute.create({
id: `${msg.tx.hash}-${msg.idx}`,
poolId: pool.id,
swapId: swap.id,
tokenInDenom: msg.msg.decodedMsg.tokenInDenom,
});
await swapRoute.save();
}

0 comments on commit 8ef5fc2

Please sign in to comment.