Skip to content

Commit

Permalink
Merge pull request #1 from oraichain/feat/xrpl-relayer
Browse files Browse the repository at this point in the history
Feat/xrpl relayer
  • Loading branch information
trung2891 authored Aug 26, 2024
2 parents a1d880e + 6113abb commit 1a723db
Show file tree
Hide file tree
Showing 26 changed files with 3,448 additions and 158 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,6 @@ dist
.pnp.*

.nx
build*
build*
.DS_Store
demo/
Binary file modified packages/contracts-build/data/cw-xrpl.wasm
Binary file not shown.
4 changes: 4 additions & 0 deletions packages/relayer/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
XRPL_RPC=
MNEMONIC_ENCRYPTED=
XRPL_SEED_ENCRYPTED=
LAST_LEDGER=
25 changes: 19 additions & 6 deletions packages/relayer/package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
{
"name": "@oraichain/xrpl-bridge-relayer",
"version": "1.0.0",
"main": "build/index.js",
"version": "1.0.1",
"main": "dist/index.js",
"bin": {
"xrplRelayer": "dist/index.js"
},
"author": "Oraichain Labs",
"files": [
"build/"
"dist/index.js"
],
"scripts": {
"build": "tsc -p tsconfig.json"
"build": "esbuild src/index.ts --bundle --minify --platform=node --external:fsevents --external:shelljs --log-level=error --outfile=dist/index.js"
},
"license": "MIT",
"publishConfig": {
"registry": "https://registry.npmjs.org/",
"access": "public"
},
"dependencies": {
"@oraichain/common": "^1.0.3",
"@oraichain/xrpl-bridge-contracts-build": "workspace:^",
"@oraichain/xrpl-bridge-contracts-sdk": "workspace:^",
"xrpl": "^4.0.0"
"@types/yargs": "^17.0.32",
"discord.js": "^14.14.1",
"esbuild": "^0.20.2",
"readline-sync": "^1.4.10",
"xrpl": "^4.0.0",
"yargs": "^17.7.2"
},
"devDependencies": {
"@oraichain/cw-simulate": "^2.8.97"
"@oraichain/cw-simulate": "^2.8.98"
}
}
3 changes: 2 additions & 1 deletion packages/relayer/src/actions/claim-fees.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { toDisplay } from "@oraichain/common";
import { CwXrplInterface } from "@oraichain/xrpl-bridge-contracts-sdk";
import { RelayerAction } from "src/type";

export default class ClaimRelayerFeesAction {
export default class ClaimRelayerFeesAction implements RelayerAction {
private readonly MIN_RELAYER_FEES_TO_CLAIM = 1; // 1*10^6

constructor(private readonly client: CwXrplInterface) {}
Expand Down
3 changes: 2 additions & 1 deletion packages/relayer/src/actions/halt-bridge.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CwXrplInterface } from "@oraichain/xrpl-bridge-contracts-sdk";
import { RelayerAction } from "src/type";

export default class HaltBridgeAction {
export default class HaltBridgeAction implements RelayerAction {
constructor(private readonly client: CwXrplInterface) {}

async takeAction() {
Expand Down
177 changes: 177 additions & 0 deletions packages/relayer/src/actions/orai-to-xrpl-operation-tx.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import { Operation } from "@oraichain/xrpl-bridge-contracts-sdk/build/CwXrpl.types";
import {
Amount,
Payment,
SignerEntry,
SignerListSet,
TicketCreate,
TrustSet,
} from "xrpl";
import { getMultisigningFee } from "../xrpl/fee";

// BuildTicketCreateTxForMultiSigning builds TicketCreate transaction operation from the contract operation.
export function buildTicketCreateTxForMultiSigning(
bridgeXRPLAddress: string,
operation: Operation
) {
if (!("allocate_tickets" in operation.operation_type)) {
throw new Error("Invalid operation type, expected allocate_tickets");
}
const tx: TicketCreate = {
TicketCount: operation.operation_type.allocate_tickets.number,
TransactionType: "TicketCreate",
Account: bridgeXRPLAddress,
};

if (operation.ticket_sequence) {
tx.TicketSequence = operation.ticket_sequence;
tx.Sequence = 0;
} else {
tx.Sequence = operation.account_sequence;
}

// important for the multi-signing
tx.SigningPubKey = "";

tx.Fee = getMultisigningFee(operation.xrpl_base_fee).toFixed(0);

return tx;
}

// BuildTrustSetTxForMultiSigning builds TrustSet transaction operation from the contract operation.
export function buildTrustSetTxForMultiSigning(
bridgeXRPLAddress: string,
operation: Operation
) {
if (!("trust_set" in operation.operation_type)) {
throw new Error("Invalid operation type, expected trust_set");
}
const trustSetType = operation.operation_type.trust_set;

const tx: TrustSet = {
TransactionType: "TrustSet",
LimitAmount: {
value: trustSetType.trust_set_limit_amount,
currency: trustSetType.currency,
issuer: trustSetType.issuer,
},
Account: bridgeXRPLAddress,
};
tx.TicketSequence = operation.ticket_sequence;
// important for the multi-signing
tx.SigningPubKey = "";
tx.Sequence = 0;

tx.Fee = getMultisigningFee(operation.xrpl_base_fee).toFixed(0);

return tx;
}

// BuildOraiToXRPLXRPLOriginatedTokenTransferPaymentTxForMultiSigning builds Payment transaction for
// XRPL originated token from the contract operation.
export function buildToXRPLXRPLOriginatedTokenTransferPaymentTxForMultiSigning(
bridgeXRPLAddress: string,
operation: Operation
) {
if (!("cosmos_to_xrpl_transfer" in operation.operation_type)) {
throw new Error("Invalid operation type, expected trust_set");
}
const oraiToXRPLTransferOperationType =
operation.operation_type.cosmos_to_xrpl_transfer;

const amount: Amount =
oraiToXRPLTransferOperationType.currency == "XRP"
? oraiToXRPLTransferOperationType.amount
: {
value: oraiToXRPLTransferOperationType.amount,
currency: oraiToXRPLTransferOperationType.currency,
issuer: oraiToXRPLTransferOperationType.issuer,
};

// if the max amount was provided set it or use nil
let maxAmount: Amount;
if (oraiToXRPLTransferOperationType.max_amount) {
maxAmount =
oraiToXRPLTransferOperationType.currency == "XRP"
? oraiToXRPLTransferOperationType.max_amount
: {
value: oraiToXRPLTransferOperationType.max_amount,
currency: oraiToXRPLTransferOperationType.currency,
issuer: oraiToXRPLTransferOperationType.issuer,
};
}

const tx = buildPaymentTx(bridgeXRPLAddress, operation, amount, maxAmount);

return tx;
}

// BuildSignerListSetTxForMultiSigning builds SignerListSet transaction operation from the contract operation.
export function buildSignerListSetTxForMultiSigning(
bridgeXRPLAddress: string,
operation: Operation
) {
if (!("rotate_keys" in operation.operation_type)) {
throw new Error("Invalid operation type, expected rotate_keys");
}
const rotateKeysOperationType = operation.operation_type.rotate_keys;

const signerEntries: SignerEntry[] = [];

for (const relayer of rotateKeysOperationType.new_relayers) {
const xrplRelayerAddress = relayer.xrpl_address;
signerEntries.push({
SignerEntry: {
Account: xrplRelayerAddress,
SignerWeight: 1,
},
});
}

const tx: SignerListSet = {
SignerQuorum: rotateKeysOperationType.new_evidence_threshold,

Account: bridgeXRPLAddress,
TransactionType: "SignerListSet",

SignerEntries: signerEntries,
};
if (operation.ticket_sequence) {
tx.TicketSequence = operation.ticket_sequence;
} else {
tx.Sequence = operation.account_sequence;
}
// important for the multi-signing
tx.SigningPubKey = "";
tx.Sequence = 0;

tx.Fee = getMultisigningFee(operation.xrpl_base_fee).toFixed(0);

return tx;
}

export function buildPaymentTx(
bridgeXRPLAddress: string,
operation: Operation,
amount: Amount,
maxAmount: Amount
) {
if (!("cosmos_to_xrpl_transfer" in operation.operation_type)) {
throw new Error("Invalid operation type, expected trust_set");
}
const recipient = operation.operation_type.cosmos_to_xrpl_transfer.recipient;
const tx: Payment = {
Destination: recipient,
Account: bridgeXRPLAddress,
TransactionType: "Payment",
Amount: amount,
SendMax: maxAmount,
};
tx.TicketSequence = operation.ticket_sequence;
// important for the multi-signing
tx.SigningPubKey = "";
tx.Sequence = 0;

tx.Fee = getMultisigningFee(operation.xrpl_base_fee).toFixed(0);
return tx;
}
Loading

0 comments on commit 1a723db

Please sign in to comment.