Skip to content

Commit

Permalink
added skip go action
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahSaso committed Jan 22, 2025
1 parent 0687e37 commit cac4bd2
Show file tree
Hide file tree
Showing 28 changed files with 2,298 additions and 1,300 deletions.
Binary file added apps/dapp/public/skipgo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added apps/sda/public/skipgo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions packages/i18n/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,7 @@
"optional": "optional",
"options": "Options",
"orUploadOne": "...or upload one below.",
"outputAmount": "Output amount",
"outputToken": "Output token",
"parameterChanges": "Parameter changes",
"passingThresholdDescription": "The proportion of voters on a single choice (Yes/No/Abstain) proposal who must vote 'Yes' for it to pass. Passing threshold works differently depending on whether your DAO has a quorum.\n- If your DAO *has a quorum*, the passing threshold is only calculated from those who voted.\n- If your DAO has *no quorum*, this is the percentage of the DAO's voting power that must vote 'yes' for a proposal to pass.",
Expand Down
11 changes: 9 additions & 2 deletions packages/state/indexer/snapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,17 @@ export const querySnapper = async <T = any>({
const response = await fetch(url)

if (response.status >= 300) {
throw new Error(
const text = await (await response.text().catch(() => '')).trim()

console.error(
`Error querying snapper for ${query} with params ${params.toString()}: ${
response.status
} ${await response.text().catch(() => '')}`.trim()
} ${response.statusText} ${text}`.trim()
)

throw new Error(
text ||
`Unknown Snapper query error: ${response.status} ${response.statusText}`
)
}

Expand Down
2 changes: 2 additions & 0 deletions packages/state/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@dao-dao/math": "2.6.0-rc.1",
"@dao-dao/utils": "2.6.0-rc.1",
"@tanstack/react-query": "^5.40.0",
"ethers": "^6.13.5",
"graphql": "^16.8.1",
"json5": "^2.2.0",
"lodash.uniq": "^4.5.0",
Expand All @@ -37,6 +38,7 @@
"@graphql-codegen/cli": "^5.0.0",
"@graphql-codegen/client-preset": "^4.1.0",
"@graphql-typed-document-node/core": "^3.2.0",
"@skip-go/client": "^0.16.5",
"@types/lodash.uniq": "^4.5.7",
"typescript": "5.4.5"
},
Expand Down
145 changes: 142 additions & 3 deletions packages/state/query/queries/skip.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
import type { MsgsDirectResponse } from '@skip-go/client'
import { QueryClient, queryOptions } from '@tanstack/react-query'

import {
AnyChain,
AnyChainSkip,
GenericToken,
GenericTokenSource,
SkipAsset,
SkipChain,
TokenType,
} from '@dao-dao/types'
import { convertSkipChainToAnyChain } from '@dao-dao/utils'
import {
convertSkipAssetToGenericToken,
convertSkipChainToAnyChain,
} from '@dao-dao/utils'

import { indexerQueries } from './indexer'

Expand All @@ -21,7 +26,7 @@ export const fetchSkipChain = async (
}: {
chainId: string
}
): Promise<AnyChain> => {
): Promise<AnyChainSkip> => {
const chain = await queryClient.fetchQuery(
indexerQueries.snapper<SkipChain>({
query: 'skip-chain',
Expand All @@ -38,6 +43,28 @@ export const fetchSkipChain = async (
return convertSkipChainToAnyChain(chain)
}

/**
* Fetch all Skip chains.
*/
export const fetchAllSkipChains = async (
queryClient: QueryClient
): Promise<AnyChainSkip[]> => {
const chains = await queryClient.fetchQuery(
indexerQueries.snapper<SkipChain[]>({
query: 'skip-chains',
parameters: {
all: true,
},
})
)

return (
chains
?.map(convertSkipChainToAnyChain)
.sort((a, b) => a.prettyName.localeCompare(b.prettyName)) ?? []
)
}

/**
* Fetch Skip asset.
*/
Expand All @@ -63,6 +90,30 @@ export const fetchSkipAsset = async (
return asset
}

/**
* Fetch all Skip assets as generic tokens.
*
* Returns a map of chainId to assets.
*/
export const fetchAllSkipAssets = async (
queryClient: QueryClient
): Promise<Record<string, GenericToken[]>> => {
const assets = await queryClient.fetchQuery(
indexerQueries.snapper<Record<string, { assets: SkipAsset[] }>>({
query: 'skip-all-assets',
})
)

return Object.fromEntries(
Object.entries(assets ?? {}).map(([chainId, { assets }]) => [
chainId,
assets
.map(convertSkipAssetToGenericToken)
.sort((a, b) => a.symbol.localeCompare(b.symbol)),
])
)
}

/**
* Fetch Skip recommended asset.
*/
Expand Down Expand Up @@ -112,6 +163,67 @@ export const fetchSkipChainPfmEnabled = async (
)
}

/**
* Fetch the route and messages for a transfer via Skip Go.
*/
export const fetchSkipGoMsgsDirect = async (
queryClient: QueryClient,
{
fromChainId,
fromTokenType,
fromDenomOrAddress,
toChainId,
toTokenType,
toDenomOrAddress,
amount,
slippageTolerancePercent,
timeoutSeconds,
addresses,
}: {
fromChainId: string
fromTokenType: TokenType
fromDenomOrAddress: string
toChainId: string
toTokenType: TokenType
toDenomOrAddress: string
amount: string
slippageTolerancePercent: number
timeoutSeconds: number
addresses: Record<string, string>
}
): Promise<MsgsDirectResponse> => {
const fromDenom =
fromTokenType === TokenType.Cw20
? 'cw20:' + fromDenomOrAddress
: fromDenomOrAddress
const toDenom =
toTokenType === TokenType.Cw20
? 'cw20:' + toDenomOrAddress
: toDenomOrAddress

const data = await queryClient.fetchQuery(
indexerQueries.snapper<MsgsDirectResponse>({
query: 'skip-go-msgs-direct',
parameters: {
fromChainId,
fromDenom,
toChainId,
toDenom,
amountIn: amount,
slippageTolerancePercent,
timeoutSeconds,
addresses: JSON.stringify(addresses),
},
})
)

if (!data) {
throw new Error('No Skip Go msgs direct found')
}

return data
}

export const skipQueries = {
/**
* Fetch Skip chain.
Expand All @@ -124,6 +236,14 @@ export const skipQueries = {
queryKey: ['skip', 'chain', options],
queryFn: () => fetchSkipChain(queryClient, options),
}),
/**
* Fetch all Skip chains.
*/
chains: (queryClient: QueryClient) =>
queryOptions({
queryKey: ['skip', 'chains'],
queryFn: () => fetchAllSkipChains(queryClient),
}),
/**
* Fetch Skip asset.
*/
Expand All @@ -135,6 +255,14 @@ export const skipQueries = {
queryKey: ['skip', 'asset', options],
queryFn: () => fetchSkipAsset(queryClient, options),
}),
/**
* Fetch all Skip assets.
*/
allAssets: (queryClient: QueryClient) =>
queryOptions({
queryKey: ['skip', 'allAssets'],
queryFn: () => fetchAllSkipAssets(queryClient),
}),
/**
* Fetch Skip recommended asset.
*/
Expand Down Expand Up @@ -172,4 +300,15 @@ export const skipQueries = {
queryKey: ['skip', 'chainPfmEnabled', options],
queryFn: () => fetchSkipChainPfmEnabled(queryClient, options),
}),
/**
* Fetch the route and messages for a transfer via Skip Go.
*/
skipGoMsgsDirect: (
queryClient: QueryClient,
options: Parameters<typeof fetchSkipGoMsgsDirect>[1]
) =>
queryOptions({
queryKey: ['skip', 'skipGoMsgsDirect', options],
queryFn: () => fetchSkipGoMsgsDirect(queryClient, options),
}),
}
43 changes: 43 additions & 0 deletions packages/state/query/queries/token.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { QueryClient, queryOptions } from '@tanstack/react-query'
import { ethers } from 'ethers'

import {
ChainId,
Expand All @@ -13,6 +14,7 @@ import {
MAINNET,
bitsongProtoRpcClientRouter,
convertChainRegistryAssetToGenericToken,
ethereumClientRouter,
getChainForChainName,
getFallbackImage,
getIbcTransferInfoFromChannel,
Expand Down Expand Up @@ -114,6 +116,39 @@ export const fetchTokenInfo = async (
}
}

if (type === TokenType.Erc20) {
const provider = await ethereumClientRouter.connect(chainId)

const strategyBaseContract = new ethers.Contract(
denomOrAddress,
[
'function decimals() view returns (uint8)',
'function symbol() view returns (string)',
],
provider
)
const [decimals, symbol] = (await Promise.all([
strategyBaseContract.decimals(),
strategyBaseContract.symbol(),
])) as [bigint, string]

return {
chainId,
type,
denomOrAddress,
symbol,
decimals: Number(decimals),
imageUrl: getFallbackImage(denomOrAddress),
source: await queryClient.fetchQuery(
tokenQueries.source(queryClient, {
chainId,
type,
denomOrAddress,
})
),
}
}

if (type === TokenType.Cw20) {
const [tokenInfo, imageUrl] = await Promise.all([
queryClient.fetchQuery(
Expand Down Expand Up @@ -293,6 +328,14 @@ export const fetchTokenSource = async (
queryClient: QueryClient,
{ chainId, type, denomOrAddress }: GenericTokenSource
): Promise<GenericTokenSource> => {
if (type === TokenType.Erc20) {
return {
chainId,
type,
denomOrAddress,
}
}

// Check if Skip API has the info.
const skipAsset = await queryClient
.fetchQuery(
Expand Down
Loading

0 comments on commit cac4bd2

Please sign in to comment.