Skip to content

Commit

Permalink
Merge pull request #150 from rabbitholegg/mmackz-symbiosis-fix
Browse files Browse the repository at this point in the history
fix(symbiosis): bump/pin sdk version and add support for new abi
  • Loading branch information
mmackz authored Dec 27, 2023
2 parents 4fa5fd5 + 61a4b2b commit 6a903fd
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 277 deletions.
5 changes: 5 additions & 0 deletions .changeset/short-eagles-carry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rabbitholegg/questdk-plugin-symbiosis": minor
---

update and pin symbiosis sdk and add support for new metaburn ABI
2 changes: 1 addition & 1 deletion packages/symbiosis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"dependencies": {
"@rabbitholegg/questdk": "2.0.0-alpha.28",
"ethers": "^5.2.0",
"symbiosis-js-sdk": "3.0.9",
"symbiosis-js-sdk": "3.1.15",
"viem": "^1.2.15"
}
}
145 changes: 44 additions & 101 deletions packages/symbiosis/src/Symbiosis.test.ts
Original file line number Diff line number Diff line change
@@ -1,138 +1,81 @@
import { GreaterThanOrEqual, apply } from '@rabbitholegg/questdk/filter'
import { apply } from '@rabbitholegg/questdk/filter'
import { describe, expect, test } from 'vitest'
import { bridge } from './Symbiosis'
import {
PASSING_TEST_TRANSACTIONS,
FAILING_TEST_TRANSACTIONS,
controlTransaction,
} from './test-transactions'
import { passingTestCases, failingTestCases } from './test-transactions'
import { metaBurnABI, metaRouteABI } from './abi'
import { ETH_CHAIN_ID, OPTIMISM_CHAIN_ID } from './constants'
import { symbiosis } from './symbiosis-sdk'

const TEST_USER = '0xB7e98B3F16CC915B9C7a321c1bd95fa406BDbabe'
const OPTIMISM_USDCe_ADDRESS = '0x7F5c764cBc14f9669B88837ca1490cCa17c31607'
import { zeroAddress, isAddress } from 'viem'
import { Chains } from './utils'
import {
bridge,
getSupportedChainIds,
getSupportedTokenAddresses,
} from './Symbiosis'

describe('Given the symbiosis plugin', () => {
describe('When handling the bridge', () => {
test('should return a valid action filter', async () => {
const filter = await bridge({
sourceChainId: OPTIMISM_CHAIN_ID,
destinationChainId: ETH_CHAIN_ID,
tokenAddress: OPTIMISM_USDCe_ADDRESS,
amount: GreaterThanOrEqual(100000n),
recipient: TEST_USER,
})

const { params } = passingTestCases[0]
const filter = await bridge(params)
expect(filter).to.deep.equal({
chainId: 10,
to: symbiosis.metaRouter(10).address,
chainId: Chains.OPTIMISM,
to: '0x0f91052dc5B4baE53d0FeA5DAe561A117268f5d2',
input: {
$abi: metaRouteABI,
_metarouteTransaction: {
approvedTokens: [OPTIMISM_USDCe_ADDRESS],
approvedTokens: { $first: zeroAddress },
amount: {
$gte: '100000',
$gte: '7500000000000000',
},
otherSideCalldata: {
$abiAbstract: metaBurnABI,
_metaBurnTransaction: {
chainID: 1,
chain2address: TEST_USER,
chainID: Chains.ARBITRUM_ONE,
chain2address: '0xa99f898530df1514a566f1a6562d62809e99557d',
},
},
},
},
})
})
})
describe('should pass filter with valid transactions', () => {
PASSING_TEST_TRANSACTIONS.forEach((testTransaction) => {
test(testTransaction.description, async () => {
const {
transaction,
destinationChainId,
tokenAddress,
amount,
recipient,
} = testTransaction

const filter = await bridge({
sourceChainId: transaction.chainId,
destinationChainId,
tokenAddress,
amount: GreaterThanOrEqual(amount),
recipient,
})
describe('should pass filter with valid transactions', () => {
passingTestCases.forEach((testCase) => {
const { transaction, description, params } = testCase
test(description, async () => {
const filter = await bridge(params)
expect(apply(transaction, filter)).to.be.true
})
})
})
describe('should not pass filter with invalid parameters', () => {
test('when sourceChainId is incorrect', async () => {
const { transaction, tokenAddress, recipient } = controlTransaction

const filter = await bridge({
sourceChainId: 1, // 42161
destinationChainId: 5000,
tokenAddress,
amount: GreaterThanOrEqual(10000n),
recipient,
})
expect(apply(transaction, filter)).to.be.false
})
test('when bridge contract address is incorrect', async () => {
const { transaction, tokenAddress, recipient } = controlTransaction

const filter = await bridge({
sourceChainId: 42161,
destinationChainId: 5000,
contractAddress: '0x1DCfbC3fA01b2a86bC3a3f43479cCe9E8D438Adc',
tokenAddress,
amount: GreaterThanOrEqual(10000n),
recipient,
})
expect(apply(transaction, filter)).to.be.false
})
FAILING_TEST_TRANSACTIONS.forEach((testTransaction) => {
test(testTransaction.description, async () => {
const {
transaction,
destinationChainId,
tokenAddress,
amount,
recipient,
} = testTransaction

const filter = await bridge({
sourceChainId: transaction.chainId,
destinationChainId,
tokenAddress,
amount: GreaterThanOrEqual(amount),
recipient,
})
describe('should not pass filter with invalid transactions', () => {
failingTestCases.forEach((testCase) => {
const { transaction, description, params } = testCase
test(description, async () => {
const filter = await bridge(params)
expect(apply(transaction, filter)).to.be.false
})
})
})
describe('control transaction should pass filter', () => {
test(controlTransaction.description, async () => {
const {
transaction,
destinationChainId,
tokenAddress,
amount,
recipient,
} = controlTransaction

const filter = await bridge({
sourceChainId: transaction.chainId,
destinationChainId,
tokenAddress,
amount: GreaterThanOrEqual(amount),
recipient,
describe('should return a valid list of tokens for each supported chain', async () => {
const chainIdArray = await getSupportedChainIds()
chainIdArray.forEach((chainId) => {
test(`for chainId: ${chainId}`, async () => {
const tokens = await getSupportedTokenAddresses(chainId)
expect(tokens).to.be.an('array')
expect(tokens).to.have.length.greaterThan(0)
expect(tokens).to.have.length.lessThan(100)
tokens.forEach((token) => {
const isValid = isAddress(token)
if (!isValid) {
console.error(
`Token address ${token} is not a valid Ethereum address`,
)
}
expect(isValid).to.be.true
})
})
expect(apply(transaction, filter)).to.be.true
})
})
})
6 changes: 4 additions & 2 deletions packages/symbiosis/src/Symbiosis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
type BridgeActionParams,
compressJson,
} from '@rabbitholegg/questdk'
import { type Address } from 'viem'
import { type Address, getAddress } from 'viem'
import { CHAIN_ID_ARRAY, CHAIN_TO_TOKENS } from './constants'
import { metaBurnABI, metaRouteABI } from './abi'
import { symbiosis } from './symbiosis-sdk'
Expand All @@ -29,7 +29,9 @@ export const bridge = async (
input: {
$abi: metaRouteABI,
_metarouteTransaction: {
approvedTokens: tokenAddress ? [tokenAddress] : undefined, // if tokenAddress is undefined, any input token will pass filter
approvedTokens: tokenAddress
? { $first: getAddress(tokenAddress) }
: undefined, // if tokenAddress is undefined, any input token will pass filter
amount: amount,
otherSideCalldata: {
$abiAbstract: metaBurnABI,
Expand Down
69 changes: 12 additions & 57 deletions packages/symbiosis/src/abi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,80 +55,35 @@ export const metaBurnABI = [
name: 'stableBridgingFee',
type: 'uint256',
},
{
internalType: 'uint256',
name: 'amount',
type: 'uint256',
},
{
internalType: 'address',
name: 'syntCaller',
type: 'address',
},
{ internalType: 'uint256', name: 'amount', type: 'uint256' },
{ internalType: 'bytes32', name: 'crossChainID', type: 'bytes32' },
{ internalType: 'address', name: 'syntCaller', type: 'address' },
{
internalType: 'address',
name: 'finalReceiveSide',
type: 'address',
},
{
internalType: 'address',
name: 'sToken',
type: 'address',
},
{
internalType: 'bytes',
name: 'finalCallData',
type: 'bytes',
},
{
internalType: 'uint256',
name: 'finalOffset',
type: 'uint256',
},
{
internalType: 'address',
name: 'chain2address',
type: 'address',
},
{
internalType: 'address',
name: 'receiveSide',
type: 'address',
},
{
internalType: 'address',
name: 'oppositeBridge',
type: 'address',
},
{ internalType: 'address', name: 'sToken', type: 'address' },
{ internalType: 'bytes', name: 'finalCallData', type: 'bytes' },
{ internalType: 'uint256', name: 'finalOffset', type: 'uint256' },
{ internalType: 'address', name: 'chain2address', type: 'address' },
{ internalType: 'address', name: 'receiveSide', type: 'address' },
{ internalType: 'address', name: 'oppositeBridge', type: 'address' },
{
internalType: 'address',
name: 'revertableAddress',
type: 'address',
},
{
internalType: 'uint256',
name: 'chainID',
type: 'uint256',
},
{
internalType: 'bytes32',
name: 'clientID',
type: 'bytes32',
},
{ internalType: 'uint256', name: 'chainID', type: 'uint256' },
{ internalType: 'bytes32', name: 'clientID', type: 'bytes32' },
],
internalType: 'struct MetaRouteStructs.MetaBurnTransaction',
name: '_metaBurnTransaction',
type: 'tuple',
},
],
name: 'metaBurnSyntheticToken',
outputs: [
{
internalType: 'bytes32',
name: 'internalID',
type: 'bytes32',
},
],
outputs: [{ internalType: 'bytes32', name: 'internalID', type: 'bytes32' }],
stateMutability: 'nonpayable',
type: 'function',
},
Expand Down
241 changes: 129 additions & 112 deletions packages/symbiosis/src/test-transactions.ts

Large diffs are not rendered by default.

63 changes: 63 additions & 0 deletions packages/symbiosis/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import type { ActionParams } from '@rabbitholegg/questdk'
import type { Address, Hash } from 'viem'

export enum Chains {
ETHEREUM = 1,
OPTIMISM = 10,
BINANCE_SMART_CHAIN = 56,
GNOSIS = 100,
POLYGON_POS = 137,
ZK_SYNC_ERA = 324,
POLYGON_ZK = 1101,
MANTLE = 5000,
BASE = 8453,
ARBITRUM_ONE = 42161,
AVALANCHE = 43114,
LINEA = 59144,
SCROLL = 534352,
}

interface Transaction {
chainId: number
from: Address
hash?: Hash
input: string
to: Address
value: string
}

export interface TestCase<T extends ActionParams> {
transaction: Transaction
params: T
description: string
}

export type TestParams<T extends ActionParams> = {
transaction: Transaction
params: T
}

/**
* Creates a test case object for a given action and transaction.
*
* This function takes a `TestParams` object that includes both a `Transaction` and
* `ActionParams`, a description of the test case, and an optional set of overrides
* for the action parameters. It returns a `TestCase` object that contains the transaction,
* the combined action parameters with any overrides applied, and the description.
*
* @param {TestParams<T>} testParams - An object containing the transaction and action parameters.
* @param {string} description - A brief description of the test case.
* @param {Partial<T>} [overrides] - Optional overrides for the action parameters.
* @returns {TestCase<T>} A test case object with the transaction, params, and description.
*/
export function createTestCase<T extends ActionParams>(
testParams: TestParams<T>,
description: string,
overrides: Partial<T> = {},
): TestCase<T> {
return {
transaction: testParams.transaction,
params: { ...testParams.params, ...overrides },
description,
}
}
Loading

0 comments on commit 6a903fd

Please sign in to comment.