Skip to content

Commit

Permalink
feat: update gateway for v3
Browse files Browse the repository at this point in the history
Signed-off-by: Gregory Hill <[email protected]>
  • Loading branch information
gregdhill committed Aug 16, 2024
1 parent 1723f48 commit 2090a76
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 17 deletions.
5 changes: 3 additions & 2 deletions sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@scure/base": "^1.1.7",
"@scure/btc-signer": "^1.3.2",
"bitcoin-address-validation": "^2.2.3",
"bitcoinjs-lib": "^6.1.6"
"bitcoinjs-lib": "^6.1.6",
"ethers": "^6.13.2"
}
}
}
105 changes: 90 additions & 15 deletions sdk/src/gateway.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,96 @@
import { ethers, AbiCoder } from "ethers";

export type EvmAddress = string;

type GatewayQuote = {
onramp_address: EvmAddress;
dust_threshold: number;
gatewayAddress: EvmAddress;
dustThreshold: number;
satoshis: number;
fee: number;
gratuity: string;
bitcoin_address: string;
tx_proof_difficulty_factor: number;
bitcoinAddress: string;
txProofDifficultyFactor: number;

// TODO: add this to API or add here
strategyAddress: EvmAddress | null,
};

type GatewayCreateOrderRequest = {
gatewayAddress: EvmAddress,
strategyAddress: EvmAddress | null,
satsToConvertToEth: number,
userAddress: EvmAddress,
gatewayExtraData: string | null,
strategyExtraData: string | null,
satoshis: number,
};

type GatewayOrderResponse = {
onramp_address: EvmAddress;
token_address: EvmAddress;
gatewayAddress: EvmAddress;
tokenAddress: EvmAddress;
txid: string;
status: boolean;
timestamp: number;
tokens: string;
satoshis: number;
fee: number;
tx_proof_difficulty_factor: number;
txProofDifficultyFactor: number;
};

type GatewayStartOrderResult = {
orderUuid: string,
opReturnHash: string,
};

export type GatewayParams = {
fromChain: 'Bitcoin', // Source chain
fromToken: 'BTC', // Source token
fromUserAddress: EvmAddress, // Source chain wallet address

amount: number | string, // Amount to transfer in satoshis

toChain: 'BOB', // Destination chain
toToken: 'wBTC', // Destination token
toUserAddress: EvmAddress, // Ending chain wallet address

// TODO: remove, can be added later
maxSlippage: 0.01, //An optional percentage value passed as a decimal between 0 and 1. (i.e 0.02 = 2%). Otherwise, slippage defaults to 3%.

// below is different from SwingSDK

gasRefill: number, // Amount of satoshis to swap for ETH
}

function calculateOpReturnHash(req: GatewayCreateOrderRequest) {
const abiCoder = new AbiCoder();
return ethers.keccak256(abiCoder.encode(
["address", "address", "uint256", "address", "bytes", "bytes"],
[
req.gatewayAddress,
req.strategyAddress || ethers.ZeroAddress,
req.satsToConvertToEth,
req.userAddress,
req.gatewayExtraData,
req.strategyExtraData
]
))
}

export class GatewayApiClient {
private baseUrl: string;

constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}

async getQuote(address: string, atomicAmount?: number | string): Promise<GatewayQuote> {
const response = await fetch(`${this.baseUrl}/quote/${address}/${atomicAmount || ''}`, {
async getQuote(gatewayParams: GatewayParams): Promise<GatewayQuote> {

// TODO: convert toToken to address
// TODO: API or SDK should handle when token is from strategy
const outputToken = gatewayParams.toToken;
const atomicAmount = gatewayParams.amount;

const response = await fetch(`${this.baseUrl}/quote/${outputToken}/${atomicAmount || ''}`, {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
Expand All @@ -41,31 +101,46 @@ export class GatewayApiClient {
}

// TODO: add error handling
async createOrder(contractAddress: string, userAddress: EvmAddress, atomicAmount: number | string): Promise<string> {
async startOrder(gatewayQuote: GatewayQuote, gatewayParams: GatewayParams): Promise<GatewayStartOrderResult> {
const request: GatewayCreateOrderRequest = {
gatewayAddress: gatewayQuote.gatewayAddress,
strategyAddress: gatewayQuote.strategyAddress,
satsToConvertToEth: gatewayParams.gasRefill,
userAddress: gatewayParams.toUserAddress,
// TODO: figure out how to get extra data
gatewayExtraData: null,
strategyExtraData: null,
satoshis: gatewayQuote.satoshis,
};

const response = await fetch(`${this.baseUrl}/order`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify({ onramp_address: contractAddress, user_address: userAddress, satoshis: atomicAmount })
body: JSON.stringify(request)
});

if (!response.ok) {
throw new Error('Failed to create order');
}

return await response.json();
const uuid = await response.json();
return {
orderUuid: uuid,
opReturnHash: calculateOpReturnHash(request),
}
}

async updateOrder(id: string, tx: string) {
const response = await fetch(`${this.baseUrl}/order/${id}`, {
async finalizeOrder(orderUuid: string, bitcoinTx: string) {
const response = await fetch(`${this.baseUrl}/order/${orderUuid}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify({ bitcoin_tx: tx })
body: JSON.stringify({ bitcoin_tx: bitcoinTx })
});

if (!response.ok) {
Expand Down

0 comments on commit 2090a76

Please sign in to comment.