Skip to content

Commit

Permalink
Cross chain transactions quotes (#133)
Browse files Browse the repository at this point in the history
* multichain quotes client request

* mult chain quotes sdk

* format code

* udate sdk version

* update multichainquote query

* update multiqoute query

* renaming multichain quote

* update sdk version

* update version in package json lock

* cross chain quote example update'
  • Loading branch information
riccardopillar authored Jun 28, 2022
1 parent dfba59d commit 23ae847
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 6 deletions.
3 changes: 2 additions & 1 deletion examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"14-delayed-transactions": "../node_modules/.bin/ts-node ./src/14-delayed-transactions",
"15-topup-fuctions": "../node_modules/.bin/ts-node ./src/15-topup-fuctions",
"16-cross-chain-quote": "../node_modules/.bin/ts-node ./src/16-cross-chain-quote.ts",
"17-superFluids-createStream": "../node_modules/.bin/ts-node ./src/17-superFluids-createStream.ts"
"17-superFluids-createStream": "../node_modules/.bin/ts-node ./src/17-superFluids-createStream.ts",
"18-cross-chain-quote": "../node_modules/.bin/ts-node ./src/18-cross-chain-quote.ts"
},
"dependencies": {
"dotenv": "^16.0.1",
Expand Down
101 changes: 101 additions & 0 deletions examples/src/18-cross-chain-quote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { BigNumberish, utils } from 'ethers';
import { ContractNames, getContractAbi } from '@etherspot/contracts';
import { EnvNames, NetworkNames, Sdk, NETWORK_NAME_TO_CHAIN_ID, BridgingQuotes } from '../../src';
import { logger } from './common';
import * as dotenv from 'dotenv';
import { TransactionRequest } from '@ethersproject/abstract-provider';
dotenv.config();

export interface ERC20Contract {
encodeApprove?(spender: string, value: BigNumberish): TransactionRequest;
callAllowance?(owner: string, spender: string): Promise<string>;
}

async function main(): Promise<void> {
if (!process.env.XDAI_PRIVATE_KEY) {
console.log('private key missing');
return null;
}
let privateKey = process.env.XDAI_PRIVATE_KEY;

const sdk = new Sdk({ privateKey: privateKey }, { env: EnvNames.MainNets, networkName: NetworkNames.Xdai });

const { wallet } = sdk.state;
const { state } = sdk;

logger.log('key account', state.account);

logger.log(
'contract account',
await sdk.computeContractAccount({
sync: false,
}),
);

await sdk.syncAccount();

logger.log('synced contract account', state.account);
logger.log('synced contract account member', state.accountMember);

const XdaiUSDC = '0xDDAfbb505ad214D7b80b1f830fcCc89B60fb7A83'; // Xdai - USDC
const BnbDai = '0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174'; // Matic - Dai

const fromChainId: number = NETWORK_NAME_TO_CHAIN_ID[NetworkNames.Xdai];
const toChainId: number = NETWORK_NAME_TO_CHAIN_ID[NetworkNames.Matic];
const fromTokenAddress: string = XdaiUSDC;
const toTokenAddress: string = BnbDai;

// xDai USDC has 6 decimals
const fromAmount = utils.parseEther('0.000000000001'); // 0.1 USDC
const quoteRequestPayload = {
fromChainId: fromChainId,
toChainId: toChainId,
fromTokenAddress: fromTokenAddress,
toTokenAddress: toTokenAddress,
fromAmount: fromAmount,
};
console.log(quoteRequestPayload);
const quotes: BridgingQuotes = await sdk.getMultiChainQuotes(quoteRequestPayload);

console.log('Quotes');
console.log(quotes);

if(quotes.items.length > 0 ) {
// Select the first quote
const quote = quotes.items[0];
const tokenAddres = quote.estimate.data.fromToken.address;
const approvalAddress = quote.estimate.approvalAddress;
const amount = quote.estimate.data.fromTokenAmount;

// Build the approval transaction request
const abi = getContractAbi(ContractNames.ERC20Token);
const erc20Contract = sdk.registerContract<ERC20Contract>('erc20Contract', abi, tokenAddres);
const approvalTransactionRequest: TransactionRequest = erc20Contract.encodeApprove(approvalAddress, amount);
logger.log('Approval transaction request', approvalTransactionRequest);

// Batch the approval transaction
logger.log(
'gateway batch approval transaction',
await sdk.batchExecuteAccountTransaction({
to: approvalTransactionRequest.to,
data: approvalTransactionRequest.data,
value: approvalTransactionRequest.value,
}),
);

// Batch the cross chain transaction
const { to, value, data }: TransactionRequest = quote.transaction;
logger.log(
'gateway batch transfer token transaction',
await sdk.batchExecuteAccountTransaction({ to, data: data, value }),
);

// Estimate and submit the transactions to the Gateway
logger.log('estimated batch', await sdk.estimateGatewayBatch());
logger.log('submitted batch', await sdk.submitGatewayBatch());
}
}

main()
.catch(logger.error)
.finally(() => process.exit());
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "etherspot",
"version": "1.33.4",
"version": "1.33.5",
"description": "Etherspot SDK",
"keywords": [
"ether",
Expand Down
6 changes: 4 additions & 2 deletions src/sdk/env/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ export enum EnvNames {
export const SUPPORTED_ENVS: { [key: string]: Env } = {
[EnvNames.MainNets]: {
apiOptions: {
host: 'etherspot.pillarproject.io',
useSsl: true,
// host: 'etherspot.pillarproject.io',
// useSsl: true,
host: 'localhost',
port: 4000,
},
networkOptions: {
supportedNetworkNames: [
Expand Down
53 changes: 53 additions & 0 deletions src/sdk/exchange/classes/exchange-bridging-quote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
interface ITranscation {
data: string;
to: string;
value: string;
from: string;
chainId: number;
}

interface IApprovalData {
approvalAddress: string;
amount: string;
}

interface Token {
address: string;
symbol: string;
decimals: number;
chainId: number;
name: string;
logoURI: string;
}

interface GasCost {
limit: string;
amountUSD: string;
token: Token;
}

interface Data {
fromToken: Token;
toToken: Token;
toTokenAmount: string;
fromTokenAmount: string;
estimatedGas: string;
}
interface IEstimate {
fromAmount: string;
toAmount: string;
toAmountMin: string;
approvalAddress: string;
gasCosts: GasCost;
data: Data;
}
export class BridgingQuote {
provider: string;
approvalData: IApprovalData | null;
transaction: ITranscation;
estimate: IEstimate
}

export class BridgingQuotes {
items: BridgingQuote[];
}
1 change: 1 addition & 0 deletions src/sdk/exchange/classes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './cross-chain-bridge-token';
export * from './exchange-offer';
export * from './exchange-offers';
export * from './exchange-cross-chain-quote';
export * from './exchange-bridging-quote';
104 changes: 104 additions & 0 deletions src/sdk/exchange/exchange.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
CrossChainBridgeRoutes,
CrossChainBridgeBuildTXResponse,
CrossChainQuote,
BridgingQuotes,
} from './classes';

import { PaginatedTokens } from '../assets';
Expand Down Expand Up @@ -127,6 +128,109 @@ export class ExchangeService extends Service {
return result ? result : null;
}

async getMultiChainQuotes(
fromTokenAddress: string,
toTokenAddress: string,
fromChainId: number,
toChainId: number,
fromAmount: BigNumber,
): Promise<BridgingQuotes> {
const { apiService, accountService } = this.services;

const account = accountService.accountAddress;

const { result } = await apiService.query<{
result: BridgingQuotes;
}>(
gql`
query(
$account: String!
$fromTokenAddress: String!
$toTokenAddress: String!
$fromAmount: BigNumber!
$fromChainId: Int
$toChainId: Int
) {
result: getMultiChainQuotes(
account: $account
fromTokenAddress: $fromTokenAddress
toTokenAddress: $toTokenAddress
fromAmount: $fromAmount
fromChainId: $fromChainId
toChainId: $toChainId
) {
items {
provider
approvalData {
approvalAddress
amount
}
transaction {
data
to
value
from
chainId
}
estimate {
approvalAddress
fromAmount
toAmount
gasCosts {
limit
amountUSD
token {
address
symbol
decimals
logoURI
chainId
name
}
}
data {
fromToken {
address
symbol
decimals
logoURI
chainId
name
}
toToken {
address
symbol
decimals
logoURI
chainId
name
}
toTokenAmount
estimatedGas
}
}
}
}
}
`,
{
variables: {
account,
fromTokenAddress,
toTokenAddress,
fromChainId,
toChainId,
fromAmount,
},
models: {
result: BridgingQuotes,
},
},
);

return result ? result : null;
}

async getExchangeOffers(
fromTokenAddress: string,
toTokenAddress: string,
Expand Down
32 changes: 32 additions & 0 deletions src/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ import {
ExchangeService,
CrossChainBridgeBuildTXResponse,
CrossChainQuote,
BridgingQuotes,
} from './exchange';

import { FaucetService } from './faucet';
Expand Down Expand Up @@ -1319,6 +1320,7 @@ export class Sdk {
buildCrossChainBridgeTransaction(dto: CrossChainBridgeRoute): Promise<CrossChainBridgeBuildTXResponse> {
return this.services.exchangeService.buildCrossChainBridgeTransaction(dto);
}

/**
* gets cross chain quote
* @param dto
Expand Down Expand Up @@ -1349,6 +1351,36 @@ export class Sdk {
);
}

/**
* gets multi chain quotes
* @param dto
* @return Promise<MutliChainQuotes>
*/
async getMultiChainQuotes(dto: GetExchangeCrossChainQuoteDto): Promise<BridgingQuotes> {
const { fromChainId, toChainId, fromTokenAddress, toTokenAddress, fromAmount } = await validateDto(
dto,
GetExchangeCrossChainQuoteDto,
{
addressKeys: ['fromTokenAddress', 'toTokenAddress'],
},
);

await this.require({
session: true,
});

let { chainId } = this.services.networkService;
chainId = fromChainId ? fromChainId : chainId;

return this.services.exchangeService.getMultiChainQuotes(
fromTokenAddress,
toTokenAddress,
chainId,
toChainId,
BigNumber.from(fromAmount),
);
}

// p2p payments

/**
Expand Down

0 comments on commit 23ae847

Please sign in to comment.