Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
8e09fb2
feat(realunit): adjust KYC level requirements based on amount (#2771)
TaprootFreak Dec 31, 2025
bc6c419
feat(realunit): adjust KYC requirements and set Level 20 on registrat…
TaprootFreak Dec 31, 2025
620b2a4
Fix mail login redirect to use /account instead of /kyc (#2773)
TaprootFreak Dec 31, 2025
2e8a697
Add bank holidays for 2026 (#2780)
TaprootFreak Dec 31, 2025
6229163
Add vIBAN search to compliance endpoint (#2775)
TaprootFreak Jan 1, 2026
36c0259
Fix email UX: display button before fallback link (#2774)
TaprootFreak Jan 1, 2026
630d240
Add Liechtenstein bank holidays 2026 and prevent fiat output on holid…
TaprootFreak Jan 1, 2026
d9c2b3c
Add Sepolia USDT token asset (#2783)
TaprootFreak Jan 1, 2026
a55f3ff
Add Sepolia USDT to asset seed file (#2784)
TaprootFreak Jan 1, 2026
0bd51e6
Fix sell deposit tx creation with missing user address and deposit re…
TaprootFreak Jan 1, 2026
c15ebb7
chore(ci): add npm caching and improve build tooling (#2788)
TaprootFreak Jan 2, 2026
cb1705e
feat: add EIP-7702 delegation support for gasless Sell and Swap
TaprootFreak Jan 2, 2026
f86a6b3
Skip Bitcoin pay-in processing when node is unavailable (#2789)
TaprootFreak Jan 2, 2026
e92f751
Skip bank transaction check when Olky bank is not configured (#2790)
TaprootFreak Jan 2, 2026
a81be21
Skip blockchain services when config is unavailable (#2791)
TaprootFreak Jan 2, 2026
289d7f7
Add warning logs for missing config (#2793)
TaprootFreak Jan 2, 2026
bf08a27
feat: different exceptions for buy endpoint (#2794)
xlamn Jan 2, 2026
f690d42
Log missing config warnings only once (#2795)
TaprootFreak Jan 2, 2026
0966205
fix(swap): correct misleading includeTx default value (#2792)
TaprootFreak Jan 2, 2026
5a55525
Fix flaky timing test in lock.spec.ts (#2796)
TaprootFreak Jan 2, 2026
0cedeb4
feat(gs): add debug endpoint for secure database queries (#2770)
TaprootFreak Jan 3, 2026
3a80613
feat(realunit): add dev payment simulation for REALU purchases (#2798)
TaprootFreak Jan 3, 2026
74cf18b
ci: add automatic release PR workflow (#2800)
TaprootFreak Jan 3, 2026
325ff26
ci: add type-check, format-check and security audit to pipelines (#2803)
TaprootFreak Jan 3, 2026
17ddd88
fix(gs): harden FOR XML/JSON check and add security tests (#2799)
TaprootFreak Jan 3, 2026
dd53c04
perf: parallelize async operations in swap quote API (#2805)
TaprootFreak Jan 3, 2026
a9bc5fe
fix(security): resolve all CodeQL security findings (#2806)
TaprootFreak Jan 3, 2026
7d91ed8
feat(cron): add logging for skipped cron jobs (#2807)
TaprootFreak Jan 3, 2026
2b3ec62
[NOTASK] Refactoring Debug endpoint
Yannick1712 Jan 3, 2026
73dc64b
fix(security): resolve remaining CodeQL security findings (#2809)
TaprootFreak Jan 3, 2026
64aeeb4
[DEV-4527] delete usedRef when merging with ref user
Yannick1712 Jan 3, 2026
5b0c43e
fix(gs): replace semicolon regex with string loop to avoid CodeQL fal…
TaprootFreak Jan 3, 2026
c49a5d2
Add userNonce to EIP-7702 delegation data (#2813)
TaprootFreak Jan 3, 2026
68b6c33
Disable EIP-7702 delegation for sell/swap transactions (#2816)
TaprootFreak Jan 3, 2026
26fd674
test(eip7702): skip tests while delegation is disabled (#2817)
TaprootFreak Jan 3, 2026
eba44a5
Add RealUnit sell endpoint with EIP-7702 support (#2818)
TaprootFreak Jan 3, 2026
6007df0
[NOTASK] remove unused service import
Yannick1712 Jan 4, 2026
0e69482
fix(realunit): add security validation for sell confirmation (#2819)
TaprootFreak Jan 4, 2026
96cfa5f
feat: Replace EIP-7702 eth_sign with EIP-5792 wallet_sendCalls (#2822)
TaprootFreak Jan 4, 2026
b3eb7c8
feat: differentiate trading errors by KYC level (#2823)
TaprootFreak Jan 4, 2026
0f679e4
test(realunit): add comprehensive unit tests for RealUnitDevService (…
TaprootFreak Jan 5, 2026
81f5b70
style(realunit): fix prettier formatting in dev service tests
TaprootFreak Jan 5, 2026
e3f815b
feat: auto-fill BuyFiat creditor data in FiatOutput (#2824)
TaprootFreak Jan 5, 2026
5fdf6b4
fix: add missing SellRepository to FiatOutputModule (#2825)
TaprootFreak Jan 5, 2026
a16c7a1
feat: EIP-7702 gasless transaction support via DFX relayer (#2826)
TaprootFreak Jan 5, 2026
1298a50
feat: auto-fill and validate creditor fields for FiatOutput (#2828)
TaprootFreak Jan 5, 2026
645f062
refactor: consolidate creditor fields into single JSON column (#2829)
TaprootFreak Jan 5, 2026
f07e57b
chore: remove allowlist and bank endpoints. (#2827)
xlamn Jan 5, 2026
54773d2
[NOTASK] remove unused import
Yannick1712 Jan 5, 2026
8f6fad8
feat: EIP-7702 gasless via Pimlico ERC-4337 (all chains) (#2834)
TaprootFreak Jan 5, 2026
20863fe
[NO-TASK] Cleanup
davidleomay Jan 5, 2026
eb3d415
fix: add creditor data fallback in refundBankTx methods (#2835)
TaprootFreak Jan 5, 2026
9b4a39a
[NO-TASK] Cleanup 2
davidleomay Jan 5, 2026
c4492ae
[NO-TASK] Cleanup 3
davidleomay Jan 5, 2026
845e6e0
fix: always show fixed IBAN and name for bank refunds (#2836)
TaprootFreak Jan 5, 2026
2ff74ad
feat(eip7702): Add integration tests for gasless E2E flow (#2837)
TaprootFreak Jan 6, 2026
a9a1c66
fix: improve refund flow validation and error handling (#2838)
TaprootFreak Jan 6, 2026
29616c2
fix(sell,swap): only include eip5792 data when user has zero native b…
TaprootFreak Jan 6, 2026
7df3689
fix: critical refund flow bugs - inverted validation and field fallba…
TaprootFreak Jan 6, 2026
cc738ee
feat(swap): add gasless transaction support for Swap flow (#2841)
TaprootFreak Jan 6, 2026
b7f03f0
ci: optimize workflow step order and remove redundant type-check (#2843)
TaprootFreak Jan 6, 2026
8fc31d3
feat(aml): skip phone verification for users referred by trusted refe…
TaprootFreak Jan 6, 2026
968da16
[NO-TASK] Fixed migration
davidleomay Jan 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,10 @@ EVM_CUSTODY_SEED=
EVM_WALLETS=
EVM_DELEGATION_ENABLED=true

# Pimlico Paymaster for EIP-5792 gasless transactions
# Get your API key from https://dashboard.pimlico.io/
PIMLICO_API_KEY=

ETH_WALLET_ADDRESS=
ETH_WALLET_PRIVATE_KEY=xxx

Expand Down
6 changes: 6 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
name: "DFX API CodeQL Config"

# Exclude infrastructure scripts that intentionally handle sensitive data
# rpcauth.py is a CLI tool that generates Bitcoin RPC credentials and must output them
paths-ignore:
- infrastructure/scripts/rpcauth.py
25 changes: 16 additions & 9 deletions .github/workflows/api-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches: [develop]
workflow_dispatch:

permissions:
contents: read

env:
AZURE_WEBAPP_NAME: app-dfx-api-dev
AZURE_WEBAPP_PACKAGE_PATH: '.'
Expand All @@ -22,27 +25,31 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install packages
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
retry_on: error
command: |
npm ci
command: npm ci

- name: Run linter
run: npm run lint

- name: Format check
run: npm run format:check

- name: Build code
run: |
npm run build
run: npm run build

- name: Run tests
run: |
npm run test
run: npm run test

- name: Run linter
run: |
npm run lint
- name: Security audit
run: npm audit --audit-level=high
continue-on-error: true

- name: Deploy to Azure App Service (DEV)
uses: azure/webapps-deploy@v3
Expand Down
25 changes: 16 additions & 9 deletions .github/workflows/api-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ on:
- develop
workflow_dispatch:

permissions:
contents: read

env:
NODE_VERSION: '20.x'

Expand All @@ -23,24 +26,28 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install packages
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
retry_on: error
command: |
npm ci
command: npm ci

- name: Run linter
run: npm run lint

- name: Format check
run: npm run format:check

- name: Build code
run: |
npm run build
run: npm run build

- name: Run tests
run: |
npm run test
run: npm run test

- name: Run linter
run: |
npm run lint
- name: Security audit
run: npm audit --audit-level=high
continue-on-error: true
25 changes: 16 additions & 9 deletions .github/workflows/api-prd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
branches: [master]
workflow_dispatch:

permissions:
contents: read

env:
AZURE_WEBAPP_NAME: app-dfx-api-prd
AZURE_WEBAPP_PACKAGE_PATH: '.'
Expand All @@ -22,27 +25,31 @@ jobs:
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'

- name: Install packages
uses: nick-fields/retry@v3
with:
timeout_minutes: 10
max_attempts: 3
retry_on: error
command: |
npm ci
command: npm ci

- name: Run linter
run: npm run lint

- name: Format check
run: npm run format:check

- name: Build code
run: |
npm run build
run: npm run build

- name: Run tests
run: |
npm run test
run: npm run test

- name: Run linter
run: |
npm run lint
- name: Security audit
run: npm audit --audit-level=high
continue-on-error: true

- name: Deploy to Azure App Service (PRD)
uses: azure/webapps-deploy@v3
Expand Down
70 changes: 70 additions & 0 deletions .github/workflows/auto-release-pr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Auto Release PR

on:
push:
branches: [develop]
workflow_dispatch:

permissions:
contents: read
pull-requests: write

concurrency:
group: auto-release-pr
cancel-in-progress: false

jobs:
create-release-pr:
name: Create Release PR
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Fetch master branch
run: git fetch origin master

- name: Check for existing PR
id: check-pr
run: |
PR_COUNT=$(gh pr list --base master --head develop --state open --json number --jq 'length')
echo "pr_exists=$([[ $PR_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "::notice::Open PRs from develop to master: $PR_COUNT"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Check for differences
id: check-diff
if: steps.check-pr.outputs.pr_exists == 'false'
run: |
DIFF_COUNT=$(git rev-list --count origin/master..origin/develop)
echo "has_changes=$([[ $DIFF_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT
echo "commit_count=$DIFF_COUNT" >> $GITHUB_OUTPUT
echo "::notice::Commits ahead of master: $DIFF_COUNT"

- name: Create Release PR
if: steps.check-pr.outputs.pr_exists == 'false' && steps.check-diff.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMMIT_COUNT: ${{ steps.check-diff.outputs.commit_count }}
run: |
printf '%s\n' \
"## Automatic Release PR" \
"" \
"This PR was automatically created after changes were pushed to develop." \
"" \
"**Commits:** ${COMMIT_COUNT} new commit(s)" \
"" \
"### Checklist" \
"- [ ] Review all changes" \
"- [ ] Verify CI passes" \
"- [ ] Approve and merge when ready for production" \
> /tmp/pr-body.md

gh pr create \
--base master \
--head develop \
--title "Release: develop -> master" \
--body-file /tmp/pr-body.md
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,4 @@ placeholder.env
thunder-tests/env
.claude/settings.local.json
.api.pid
CLAUDE.md
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ module.exports = tseslint.config(
'no-return-await': 'off',
'no-console': ['warn'],
'@typescript-eslint/return-await': ['warn', 'in-try-catch'],
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
Expand Down
25 changes: 25 additions & 0 deletions migration/1767291858000-AddSepoliaUSDT.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { MigrationInterface, QueryRunner } = require("typeorm");

module.exports = class AddSepoliaUSDT1767291858000 {
name = 'AddSepoliaUSDT1767291858000'

async up(queryRunner) {
await queryRunner.query(`
INSERT INTO "dbo"."asset" (
"name", "type", "buyable", "sellable", "chainId", "dexName", "category", "blockchain", "uniqueName", "description",
"comingSoon", "decimals", "paymentEnabled", "refundEnabled", "cardBuyable", "cardSellable", "instantBuyable", "instantSellable",
"financialType", "ikna", "personalIbanEnabled", "amlRuleFrom", "amlRuleTo", "priceRuleId",
"approxPriceUsd", "approxPriceChf", "approxPriceEur"
) VALUES (
'USDT', 'Token', 0, 1, '0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0', 'USDT', 'Public', 'Sepolia', 'Sepolia/USDT', 'Tether',
0, 6, 0, 1, 0, 0, 0, 0,
'USD', 0, 0, 0, 0, 40,
1, 0.78851, 0.849
)
`);
}

async down(queryRunner) {
await queryRunner.query(`DELETE FROM "dbo"."asset" WHERE "uniqueName" = 'Sepolia/USDT'`);
}
}
25 changes: 25 additions & 0 deletions migration/1767435900000-AddSepoliaREALU.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const { MigrationInterface, QueryRunner } = require("typeorm");

module.exports = class AddSepoliaREALU1767435900000 {
name = 'AddSepoliaREALU1767435900000'

async up(queryRunner) {
await queryRunner.query(`
INSERT INTO "dbo"."asset" (
"name", "type", "buyable", "sellable", "chainId", "dexName", "category", "blockchain", "uniqueName", "description",
"comingSoon", "decimals", "paymentEnabled", "refundEnabled", "cardBuyable", "cardSellable", "instantBuyable", "instantSellable",
"financialType", "ikna", "personalIbanEnabled", "amlRuleFrom", "amlRuleTo", "priceRuleId",
"approxPriceUsd", "approxPriceChf", "approxPriceEur", "sortOrder"
) VALUES (
'REALU', 'Token', 0, 0, '0x0add9824820508dd7992cbebb9f13fbe8e45a30f', 'REALU', 'Public', 'Sepolia', 'Sepolia/REALU', 'RealUnit Shares (Testnet)',
0, 0, 0, 1, 0, 0, 0, 0,
'Other', 0, 0, 0, 0, 61,
1.711564371, 1.349572115, 1.453103607, 99
)
`);
}

async down(queryRunner) {
await queryRunner.query(`DELETE FROM "dbo"."asset" WHERE "uniqueName" = 'Sepolia/REALU'`);
}
}
31 changes: 31 additions & 0 deletions migration/1767611859179-RefactorCreditorDataToJson.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @typedef {import('typeorm').MigrationInterface} MigrationInterface
* @typedef {import('typeorm').QueryRunner} QueryRunner
*/

/**
* @class
* @implements {MigrationInterface}
*/
module.exports = class RefactorCreditorDataToJson1767611859179 {
name = 'RefactorCreditorDataToJson1767611859179'

/**
* @param {QueryRunner} queryRunner
*/
async up(queryRunner) {
// Add new JSON column to buy_crypto
await queryRunner.query(`ALTER TABLE "buy_crypto" ADD "chargebackCreditorData" nvarchar(MAX)`);

// Add new JSON column to bank_tx_return
await queryRunner.query(`ALTER TABLE "bank_tx_return" ADD "chargebackCreditorData" nvarchar(MAX)`);
}

/**
* @param {QueryRunner} queryRunner
*/
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "bank_tx_return" DROP COLUMN "chargebackCreditorData"`);
await queryRunner.query(`ALTER TABLE "buy_crypto" DROP COLUMN "chargebackCreditorData"`);
}
}
27 changes: 27 additions & 0 deletions migration/1767715439412-AddUserDataIsTrustedReferrer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* @typedef {import('typeorm').MigrationInterface} MigrationInterface
* @typedef {import('typeorm').QueryRunner} QueryRunner
*/

/**
* @class
* @implements {MigrationInterface}
*/
module.exports = class AddUserDataIsTrustedReferrer1767715439412 {
name = 'AddUserDataIsTrustedReferrer1767715439412'

/**
* @param {QueryRunner} queryRunner
*/
async up(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_data" ADD "isTrustedReferrer" bit NOT NULL CONSTRAINT "DF_37c1348125fec15f1c48f62d455" DEFAULT 0`);
}

/**
* @param {QueryRunner} queryRunner
*/
async down(queryRunner) {
await queryRunner.query(`ALTER TABLE "user_data" DROP CONSTRAINT "DF_37c1348125fec15f1c48f62d455"`);
await queryRunner.query(`ALTER TABLE "user_data" DROP COLUMN "isTrustedReferrer"`);
}
}
2 changes: 2 additions & 0 deletions migration/seed/asset.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
id,name,type,buyable,sellable,chainId,sellCommand,dexName,category,blockchain,uniqueName,description,comingSoon,sortOrder,approxPriceUsd,ikna,priceRuleId,approxPriceChf,cardBuyable,cardSellable,instantBuyable,instantSellable,financialType,decimals,paymentEnabled,amlRuleFrom,amlRuleTo,approxPriceEur,refundEnabled
408,REALU,Token,FALSE,FALSE,0x0add9824820508dd7992cbebb9f13fbe8e45a30f,,REALU,Public,Sepolia,Sepolia/REALU,RealUnit Shares (Testnet),FALSE,99,1.711564371,FALSE,61,1.349572115,FALSE,FALSE,FALSE,FALSE,Other,0,FALSE,0,0,1.453103607,TRUE
407,USDT,Token,FALSE,TRUE,0xaa8e23fb1079ea71e0a56f48a2aa51851d8433d0,,USDT,Public,Sepolia,Sepolia/USDT,Tether,FALSE,,1,FALSE,40,0.78851,FALSE,FALSE,FALSE,FALSE,USD,6,FALSE,0,0,0.849,TRUE
406,ADA,Coin,TRUE,TRUE,,,ADA,Public,Cardano,Cardano/ADA,Cardano,FALSE,,0.3492050313,FALSE,63,0.2753489034,FALSE,FALSE,FALSE,FALSE,Other,6,FALSE,0,0,0.2964721043,TRUE
405,EUR,Custody,FALSE,FALSE,,,EUR,Private,Yapeal,Yapeal/EUR,,FALSE,,1.17786809,FALSE,39,0.9287514723,FALSE,FALSE,FALSE,FALSE,EUR,,FALSE,0,0,1,TRUE
404,CHF,Custody,FALSE,FALSE,,,CHF,Private,Yapeal,Yapeal/CHF,,FALSE,,1.268227427,FALSE,37,1,FALSE,FALSE,FALSE,FALSE,CHF,,FALSE,0,0,1.076714309,TRUE
Expand Down
Loading
Loading