This repository has been archived by the owner on Jul 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bcd322c
commit 1a3fa87
Showing
11 changed files
with
465 additions
and
716 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
name: Bot 'XRP on Mère Denis' | ||
on: | ||
push: | ||
branches: | ||
- family/ripple | ||
|
||
jobs: | ||
start-runner: | ||
name: "start ec2 instance (Linux)" | ||
if: ${{ always() }} | ||
uses: ledgerhq/actions/.github/workflows/start-linux-runner.yml@main | ||
secrets: | ||
CI_BOT_TOKEN: ${{ secrets.CI_BOT_TOKEN }} | ||
|
||
stop-runner: | ||
name: "stop ec2 instance (Linux)" | ||
needs: [start-runner, run-bot] | ||
uses: ledgerhq/actions/.github/workflows/stop-linux-runner.yml@main | ||
if: ${{ always() }} | ||
with: | ||
label: ${{ needs.start-runner.outputs.label }} | ||
ec2-instance-id: ${{ needs.start-runner.outputs.ec2-instance-id }} | ||
secrets: | ||
CI_BOT_TOKEN: ${{ secrets.CI_BOT_TOKEN }} | ||
|
||
run-bot: | ||
needs: [start-runner] | ||
runs-on: ${{ needs.start-runner.outputs.label }} | ||
steps: | ||
- name: prepare runner | ||
run: | | ||
sudo growpart /dev/nvme0n1 1 | ||
sudo resize2fs /dev/nvme0n1p1 | ||
- uses: actions/checkout@v2 | ||
- name: Retrieving coin apps | ||
uses: actions/checkout@v2 | ||
with: | ||
repository: LedgerHQ/coin-apps | ||
token: ${{ secrets.PAT }} | ||
path: coin-apps | ||
- uses: actions/setup-node@master | ||
with: | ||
node-version: 14.x | ||
- name: install yarn | ||
run: npm i -g yarn | ||
- name: pull docker image | ||
run: docker pull ghcr.io/ledgerhq/speculos | ||
- name: kill apt-get | ||
run: sudo killall -w apt-get apt || echo OK | ||
- name: Install linux deps | ||
run: sudo apt-get install -y libusb-1.0-0-dev jq | ||
- name: Install dependencies | ||
run: | | ||
yarn global add yalc | ||
yarn --frozen-lockfile | ||
yarn ci-setup-cli | ||
- name: BOT | ||
env: | ||
SEED: ${{ secrets.SEED1 }} | ||
VERBOSE_FILE: bot-tests.txt | ||
GITHUB_SHA: ${GITHUB_SHA} | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
GITHUB_RUN_ID: ${{ github.run_id }} | ||
GITHUB_WORKFLOW: ${{ github.workflow }} | ||
SLACK_API_TOKEN: ${{ secrets.SLACK_API_TOKEN }} | ||
SLACK_CHANNEL: ci-xrp-ll | ||
BOT_FILTER_FAMILY: ripple | ||
EXPERIMENTAL_CURRENCIES_JS_BRIDGE: ripple | ||
run: COINAPPS=$PWD/coin-apps yarn ci-test-bot | ||
timeout-minutes: 120 | ||
- name: Run coverage | ||
if: failure() || success() | ||
run: CODECOV_TOKEN=${{ secrets.CODECOV_TOKEN }} npx codecov | ||
- name: upload logs | ||
if: failure() || success() | ||
uses: actions/upload-artifact@v1 | ||
with: | ||
name: bot-tests.txt | ||
path: bot-tests.txt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,185 +1,120 @@ | ||
import { BigNumber } from "bignumber.js"; | ||
import { | ||
parseCurrencyUnit, | ||
getCryptoCurrencyById, | ||
formatCurrencyUnit, | ||
} from "../currencies"; | ||
import { getEnv } from "../env"; | ||
import { RippleAPI } from "ripple-lib"; | ||
import { Payment } from "ripple-lib/dist/npm/transaction/payment"; | ||
import { TransactionsOptions } from "ripple-lib/dist/npm/ledger/transactions"; | ||
import network from "../network"; | ||
import { parseCurrencyUnit, getCryptoCurrencyById } from "../currencies"; | ||
|
||
type AsyncApiFunction = (api: RippleAPI) => Promise<any>; | ||
|
||
type XRPInstruction = { | ||
fee: string; | ||
maxLedgerVersionOffset: number; | ||
}; | ||
|
||
const rippleUnit = getCryptoCurrencyById("ripple").units[0]; | ||
|
||
const defaultEndpoint = () => getEnv("API_RIPPLE_WS"); | ||
const defaultEndpoint = () => getEnv("API_RIPPLE_RPC"); | ||
|
||
export const connectionTimeout = 30 * 1000; // default connectionTimeout is 2s and make the specs bot failed | ||
|
||
const WEBSOCKET_DEBOUNCE_DELAY = 30000; | ||
let api; | ||
let pendingQueries: Promise<any>[] = []; | ||
let apiDisconnectTimeout; | ||
|
||
/** | ||
* Connects to Substrate Node, executes calls then disconnects | ||
* | ||
* @param {*} execute - the calls to execute on api | ||
*/ | ||
async function withApi( | ||
execute: AsyncApiFunction, | ||
endpointConfig: string | null | undefined = null | ||
): Promise<any> { | ||
const server = endpointConfig || defaultEndpoint(); | ||
|
||
// If client is instanciated already, ensure it is connected & ready | ||
if (api) { | ||
try { | ||
if (!(await api.isConnected)) { | ||
throw new Error("XRP WS is not connected"); | ||
} | ||
} catch (err) { | ||
// definitely not connected... | ||
api = null; | ||
pendingQueries = []; | ||
} | ||
} | ||
|
||
if (!api) { | ||
api = new RippleAPI({ | ||
server, | ||
}); | ||
// https://github.com/ripple/ripple-lib/issues/1196#issuecomment-583156895 | ||
// We can't add connectionTimeout to the constructor | ||
// We need to add this config to allow the bot to not timeout on github action | ||
// but it will throw a 'additionalProperty "connectionTimeout" exists' | ||
// during the preparePayment | ||
api.connection._config.connectionTimeout = connectionTimeout; | ||
api.on("error", (errorCode, errorMessage) => { | ||
console.warn(`Ripple API error: ${errorCode}: ${errorMessage}`); | ||
}); | ||
await api.connect(); | ||
} | ||
|
||
cancelDebouncedDisconnect(); | ||
|
||
try { | ||
const query = execute(api); | ||
pendingQueries.push(query.catch((err) => err)); | ||
const res = await query; | ||
return res; | ||
} finally { | ||
debouncedDisconnect(); | ||
} | ||
} | ||
|
||
/** | ||
* Disconnects Websocket API client after all pending queries are flushed. | ||
*/ | ||
export const disconnect = async (): Promise<void> => { | ||
cancelDebouncedDisconnect(); | ||
|
||
if (api) { | ||
const disconnecting = api; | ||
const pending = pendingQueries; | ||
api = undefined; | ||
pendingQueries = []; | ||
await Promise.all(pending); | ||
await disconnecting.disconnect(); | ||
} | ||
}; | ||
|
||
const cancelDebouncedDisconnect = () => { | ||
if (apiDisconnectTimeout) { | ||
clearTimeout(apiDisconnectTimeout); | ||
apiDisconnectTimeout = null; | ||
} | ||
}; | ||
|
||
/** | ||
* Disconnects Websocket client after a delay. | ||
*/ | ||
const debouncedDisconnect = () => { | ||
cancelDebouncedDisconnect(); | ||
apiDisconnectTimeout = setTimeout(disconnect, WEBSOCKET_DEBOUNCE_DELAY); | ||
}; | ||
const rippleUnit = getCryptoCurrencyById("ripple").units[0]; | ||
|
||
export const parseAPIValue = (value: string): BigNumber => | ||
parseCurrencyUnit(rippleUnit, value); | ||
|
||
export const parseAPICurrencyObject = ({ | ||
currency, | ||
value, | ||
}: { | ||
currency: string; | ||
value: string; | ||
}): BigNumber => { | ||
if (currency !== "XRP") { | ||
console.warn(`RippleJS: attempt to parse unknown currency ${currency}`); | ||
return new BigNumber(0); | ||
} | ||
|
||
return parseAPIValue(value); | ||
export const submit = async (signature: string): Promise<any> => { | ||
const res = await network({ | ||
method: "POST", | ||
url: `${defaultEndpoint()}`, | ||
data: { | ||
method: "submit", | ||
params: [ | ||
{ | ||
tx_blob: signature, | ||
}, | ||
], | ||
}, | ||
}); | ||
return res.data.result; | ||
}; | ||
|
||
export const formatAPICurrencyXRP = ( | ||
amount: BigNumber | ||
): { currency: "XRP"; value: string } => { | ||
const value = formatCurrencyUnit(rippleUnit, amount, { | ||
showAllDigits: true, | ||
disableRounding: true, | ||
useGrouping: false, | ||
}); | ||
return { | ||
currency: "XRP", | ||
value, | ||
type AccountInfo = { | ||
account_data: { | ||
Account: string; | ||
Balance: string; | ||
Flags: number; | ||
LedgerEntryType: string; | ||
OwnerCount: number; | ||
PreviousTxnID: string; | ||
PreviousTxnLgrSeq: number; | ||
Sequence: number; | ||
index: string; | ||
}; | ||
error: string; | ||
}; | ||
|
||
export const preparePayment = async ( | ||
address: string, | ||
payment: Payment, | ||
instruction: XRPInstruction | ||
): Promise<any> => | ||
withApi(async (api: RippleAPI) => { | ||
return api.preparePayment(address, payment, instruction); | ||
}); | ||
|
||
export const submit = async (signature: string): Promise<any> => | ||
withApi(async (api: RippleAPI) => { | ||
return api.request("submit", { | ||
tx_blob: signature, | ||
}); | ||
}); | ||
// endpointConfig does not seem to be undestood by linter | ||
|
||
export const getAccountInfo = async ( | ||
recipient: string, | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
endpointConfig?: string | null | undefined | ||
): Promise<any> => | ||
withApi(async (api: RippleAPI) => { | ||
return api.getAccountInfo(recipient); | ||
current?: boolean | ||
): Promise<AccountInfo> => { | ||
const res = await network({ | ||
method: "POST", | ||
url: `${defaultEndpoint()}`, | ||
data: { | ||
method: "account_info", | ||
params: [ | ||
{ | ||
account: recipient, | ||
ledger_index: current ? "current" : "validated", | ||
}, | ||
], | ||
}, | ||
}); | ||
return res.data.result; | ||
}; | ||
|
||
export const getServerInfo = async ( | ||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
endpointConfig?: string | null | undefined | ||
): Promise<any> => | ||
withApi(async (api: RippleAPI) => { | ||
return api.getServerInfo(); | ||
): Promise<any> => { | ||
const res = await network({ | ||
method: "POST", | ||
url: endpointConfig ?? `${defaultEndpoint()}`, | ||
data: { | ||
method: "server_info", | ||
params: [ | ||
{ | ||
ledger_index: "validated", | ||
}, | ||
], | ||
}, | ||
}); | ||
|
||
/* eslint-enable no-unused-vars */ | ||
return res.data.result; | ||
}; | ||
|
||
export const getTransactions = async ( | ||
address: string, | ||
options: TransactionsOptions | undefined | ||
): Promise<any> => | ||
withApi(async (api: RippleAPI) => { | ||
return api.getTransactions(address, options); | ||
options: any | undefined | ||
): Promise<any> => { | ||
const res = await network({ | ||
method: "POST", | ||
url: `${defaultEndpoint()}`, | ||
data: { | ||
method: "account_tx", | ||
params: [ | ||
{ | ||
account: address, | ||
ledger_index: "validated", | ||
...options, | ||
}, | ||
], | ||
}, | ||
}); | ||
return res.data.result.transactions; | ||
}; | ||
|
||
export default async function getLedgerIndex(): Promise<number> { | ||
const ledgerResponse = await network({ | ||
method: "POST", | ||
url: `${defaultEndpoint()}`, | ||
data: { | ||
method: "ledger", | ||
params: [ | ||
{ | ||
ledger_index: "validated", | ||
}, | ||
], | ||
}, | ||
}); | ||
return ledgerResponse.data.result.ledger_index; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,5 @@ | ||
import { disconnect as rippleApiDisconnect } from "./Ripple"; | ||
import { disconnect as polkadotApiDisconnect } from "../families/polkadot/api"; | ||
|
||
export async function disconnectAll(): Promise<void> { | ||
await rippleApiDisconnect(); | ||
await polkadotApiDisconnect(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
1a3fa87
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
✅ 2 txs ($51.83) for Bot 'XRP on Mère Denis'
Details of the 2 mutations
Spec XRP (5)
Portfolio ($51.83)
Details of the 1 currencies