Skip to content

Commit

Permalink
59 subsidize fees and risk (#97)
Browse files Browse the repository at this point in the history
* remove unnecessary dependencies

* Add subsidization endpoints and change flow

* Fix linting errors
  • Loading branch information
TorstenStueber authored Aug 26, 2024
1 parent 9c48085 commit 80d6851
Show file tree
Hide file tree
Showing 36 changed files with 551 additions and 5,233 deletions.
27 changes: 3 additions & 24 deletions signer-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,56 +26,35 @@
},
"dependencies": {
"@polkadot/api": "^10.3.4",
"bcryptjs": "2.4.3",
"bluebird": "^3.5.0",
"big.js": "^6.2.1",
"body-parser": "^1.17.0",
"compression": "^1.6.2",
"cors": "^2.8.3",
"cross-env": "^7.0.3",
"dotenv-safe": "^8.2.0",
"email-templates": "^6.0.3",
"express": "^4.15.2",
"express-rate-limit": "^6.7.0",
"express-validation": "^1.0.2",
"google-auth-library": "^9.11.0",
"google-spreadsheet": "^4.1.2",
"helmet": "^4.6.0",
"http-status": "^1.0.1",
"joi": "^10.4.1",
"jwt-simple": "0.5.6",
"lodash": "^4.17.4",
"joi": "^17.13.3",
"method-override": "^3.0.0",
"moment-timezone": "^0.5.13",
"mongoose": "^5.2.17",
"morgan": "^1.8.1",
"nodemailer": "^6.3.1",
"passport": "^0.4.0",
"passport-http-bearer": "^1.0.1",
"passport-jwt": "4.0.0",
"pm2": "^5.1.0",
"pug": "^3.0.1",
"stellar-sdk": "^11.3.0",
"uuid": "^3.1.0",
"winston": "^3.1.0"
},
"devDependencies": {
"apidoc": "^0.28.1",
"chai": "^4.1.0",
"chai-as-promised": "^7.1.1",
"coveralls": "^3.0.0",
"eslint": "^7.29.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-import": "^2.2.0",
"husky": "^3.0.7",
"mocha": "^6.2.2",
"nodemon": "^2.0.1",
"nyc": "^15.1.0",
"opn-cli": "^5.0.0",
"prettier": "^2.8.7",
"sinon": "^7.5.0",
"sinon-chai": "^3.0.0",
"supertest": "^6.1.3",
"vitest": "^2.0.5"
"prettier": "^2.8.7"
}
}
70 changes: 70 additions & 0 deletions signer-service/src/api/controllers/subsidize.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const { Keypair } = require('stellar-sdk');
const { ApiPromise, WsProvider, Keyring } = require('@polkadot/api');
const Big = require('big.js');

const { PENDULUM_WSS, PENDULUM_FUNDING_SEED } = require('../../constants/constants');

const { TOKEN_CONFIG } = require('../../constants/tokenConfig');

const TOKEN_TO_SWAP = 'usdc.axl';

exports.subsidizePreSwap = async (req, res) => {
try {
const { pendulumCurrencyId, maximumSubsidyAmountRaw } = TOKEN_CONFIG[TOKEN_TO_SWAP];

const { address, amountRaw } = req.body;
console.log('Subsidize pre swap', address, amountRaw);

if (Big(amountRaw).gt(Big(maximumSubsidyAmountRaw))) {
throw new Error('Amount exceeds maximum subsidy amount');
}

const keyring = new Keyring({ type: 'sr25519' });
const fundingAccountKeypair = keyring.addFromUri(PENDULUM_FUNDING_SEED);

const wsProvider = new WsProvider(PENDULUM_WSS);
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;

await api.tx.tokens.transfer(address, pendulumCurrencyId, amountRaw).signAndSend(fundingAccountKeypair);

return res.status(200).json({ message: 'Subsidy transferred successfully' });
} catch (error) {
console.error('Error in subsidizePreSwap::', error);
return res.status(500).json({ error: 'Server error', details: error.message });
}
};

exports.subsidizePostSwap = async (req, res) => {
try {
const { address, amountRaw, token } = req.body;
console.log('Subsidize post swap', address, amountRaw, token);

const { assetCode, assetIssuer, maximumSubsidyAmountRaw } = TOKEN_CONFIG[token];

if (Big(amountRaw).gt(Big(maximumSubsidyAmountRaw))) {
throw new Error('Amount exceeds maximum subsidy amount');
}

const assetIssuerHex = `0x${Keypair.fromPublicKey(assetIssuer).rawPublicKey().toString('hex')}`;
const pendulumCurrencyId = {
Stellar: {
AlphaNum4: { code: assetCode.padEnd(4, '\0'), issuer: assetIssuerHex },
},
};

const keyring = new Keyring({ type: 'sr25519' });
const fundingAccountKeypair = keyring.addFromUri(PENDULUM_FUNDING_SEED);

const wsProvider = new WsProvider(PENDULUM_WSS);
const api = await ApiPromise.create({ provider: wsProvider });
await api.isReady;

await api.tx.tokens.transfer(address, pendulumCurrencyId, amountRaw).signAndSend(fundingAccountKeypair);

return res.status(200).json({ message: 'Subsidy transferred successfully' });
} catch (error) {
console.error('Error in subsidizePreSwap::', error);
return res.status(500).json({ error: 'Server error', details: error.message });
}
};
2 changes: 1 addition & 1 deletion signer-service/src/api/errors/extendable-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ExtendableError extends Error {
this.errors = errors;
this.status = status;
this.isPublic = isPublic;
this.isOperational = true; // This is required since bluebird 4 doesn't append it anymore.
this.isOperational = true;
this.stack = stack;
// Error.captureStackTrace(this, this.constructor.name);
}
Expand Down
54 changes: 53 additions & 1 deletion signer-service/src/api/middlewares/validators.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { SHEET_HEADER_VALUES } = require('../controllers/storage.controller');
const { TOKEN_CONFIG } = require('../../constants/tokenConfig');

const validateCreationInput = (req, res, next) => {
const { accountId, maxTime, assetCode } = req.body;
Expand Down Expand Up @@ -45,4 +46,55 @@ const validateStorageInput = (req, res, next) => {
next();
};

module.exports = { validateChangeOpInput, validateCreationInput, validateStorageInput };
const validatePreSwapSubsidizationInput = (req, res, next) => {
const { amountRaw, address } = req.body;

if (amountRaw === undefined) {
return res.status(400).json({ error: 'Missing "amountRaw" parameter' });
}

if (typeof amountRaw !== 'string') {
return res.status(400).json({ error: '"amountRaw" parameter must be a string' });
}

if (address === undefined) {
return res.status(400).json({ error: 'Missing "address" parameter' });
}

next();
};

const validatePostSwapSubsidizationInput = (req, res, next) => {
const { amountRaw, address, token } = req.body;

if (amountRaw === undefined) {
return res.status(400).json({ error: 'Missing "amountRaw" parameter' });
}

if (typeof amountRaw !== 'string') {
return res.status(400).json({ error: '"amountRaw" parameter must be a string' });
}

if (address === undefined) {
return res.status(400).json({ error: 'Missing "address" parameter' });
}

if (token === undefined) {
return res.status(400).json({ error: 'Missing "token" parameter' });
}

const tokenConfig = TOKEN_CONFIG[token];
if (tokenConfig === undefined || tokenConfig.assetCode === undefined || tokenConfig.assetIssuer === undefined) {
return res.status(400).json({ error: 'Invalid "token" parameter' });
}

next();
};

module.exports = {
validateChangeOpInput,
validateCreationInput,
validatePreSwapSubsidizationInput,
validatePostSwapSubsidizationInput,
validateStorageInput,
};
4 changes: 4 additions & 0 deletions signer-service/src/api/routes/v1/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
const express = require('express');

const stellarRoutes = require('./stellar.route');
const pendulumRoutes = require('./pendulum.route');
const storageRoutes = require('./storage.route');
const subsidizeRoutes = require('./subsidize.route');

const router = express.Router({ mergeParams: true });
const { sendStatusWithPk: sendStellarStatusWithPk } = require('../../services/stellar.service');
Expand Down Expand Up @@ -38,4 +40,6 @@ router.use('/pendulum', pendulumRoutes);
*/
router.use('/storage', storageRoutes);

router.use('/subsidize', subsidizeRoutes);

module.exports = router;
13 changes: 13 additions & 0 deletions signer-service/src/api/routes/v1/subsidize.route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const express = require('express');
const controller = require('../../controllers/subsidize.controller');
const {
validatePreSwapSubsidizationInput,
validatePostSwapSubsidizationInput,
} = require('../../middlewares/validators');

const router = express.Router({ mergeParams: true });

router.route('/preswap').post(validatePreSwapSubsidizationInput, controller.subsidizePreSwap);
router.route('/postswap').post(validatePostSwapSubsidizationInput, controller.subsidizePostSwap);

module.exports = router;
1 change: 0 additions & 1 deletion signer-service/src/constants/constants.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
const HORIZON_URL = 'https://horizon.stellar.org';
//const HORIZON_URL = 'https://horizon-testnet.stellar.org';
const BASE_FEE = '1000000';
const PENDULUM_WSS = 'wss://rpc-pendulum.prd.pendulumchain.tech';
const NETWORK = 'Pendulum';
Expand Down
6 changes: 6 additions & 0 deletions signer-service/src/constants/tokenConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ const TOKEN_CONFIG = {
assetIssuer: 'GAQRF3UGHBT6JYQZ7YSUYCIYWAF4T2SAA5237Q5LIQYJOHHFAWDXZ7NM',
vaultAccountId: '6bsD97dS8ZyomMmp1DLCnCtx25oABtf19dypQKdZe6FBQXSm',
minWithdrawalAmount: '10000000000000',
maximumSubsidyAmountRaw: '1000000000000', // 1 unit
},
'usdc.axl': {
pendulumCurrencyId: { XCM: 12 },
decimals: 6,
maximumSubsidyAmountRaw: '1000000', // 1 unit
},
};

Expand Down
2 changes: 0 additions & 2 deletions signer-service/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// make bluebird default Promise
Promise = require('bluebird'); // eslint-disable-line no-global-assign
const { Keypair } = require('stellar-sdk');
const { port, env } = require('./config/vars');
const logger = require('./config/logger');
Expand Down
Loading

0 comments on commit 80d6851

Please sign in to comment.