Skip to content

Commit

Permalink
Merge pull request #128 from fioprotocol/develop
Browse files Browse the repository at this point in the history
Develop > master for 1.10.0 release
  • Loading branch information
ericbutz authored May 27, 2022
2 parents 4ca863b + 77c5aee commit 9164479
Show file tree
Hide file tree
Showing 30 changed files with 960 additions and 229 deletions.
5 changes: 5 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,8 @@ SLACK_WEBHOOK_URL=
DISCORD_WEBHOOK_ID=
DISCORD_WEBHOOK_TOKEN=

# Insufficient Funds Fallback Account
REG_FALLBACK_ACCOUNT=
REG_FALLBACK_PERMISSION=
REG_FALLBACK_NOTIFICATION_EMAIL=

5 changes: 3 additions & 2 deletions server/api/fio-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,14 @@ class FioApi extends FioClient {
}
}

renewAddress({address, maxFee, tpid, actor}, options = {}) {
addBundlesToAddress({address, maxFee, tpid, actor, bundleSets}, options = {}) {
return {
account: 'fio.address',
name: 'renewaddress',
name: 'addbundles',
authorization: options.authorization || this.options.authorization,
data: {
fio_address: address,
bundle_sets: bundleSets,
max_fee: maxFee,
tpid,
actor: options.actor || actor
Expand Down
3 changes: 2 additions & 1 deletion server/constants.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const ACCOUNT_TYPES = {
register: 'register',
renew: 'renew'
renew: 'renew',
addBundles: 'add_bundles'
}

module.exports = {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
'use strict';

require('dotenv').config({
path: require('path').resolve(process.cwd(), '.env-server')
});

const Sequelize = require("sequelize");
const {Fio, Ecc} = require("@fioprotocol/fiojs");
const {PrivateKey} = Ecc;

const walletPrivateKey = process.env.WALLET_PRIVATE_KEY;

const walletPublicKey = PrivateKey(walletPrivateKey).toPublic().toString('FIO');

const defaultActor = Fio.accountHash(walletPublicKey);
const defaultPermission = 'active';

module.exports = {
up: async (QI, DT) => {
return QI.sequelize.transaction( async t => {
await QI.createTable('account_profile',
{
id: {
type: DT.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
actor: {
type: DT.STRING,
allowNull: false,
},
permission: {
type: DT.STRING,
allowNull: false
},
name: {
type: DT.STRING,
allowNull: true
},
is_default: {
type: DT.BOOLEAN,
allowNull: false,
defaultValue: false
},
created_at: {
type: DT.DATE,
defaultValue: Sequelize.fn('now'),
allowNull: false
},
updated_at: {
type: DT.DATE,
defaultValue: Sequelize.fn('now'),
allowNull: false
},
deleted_at: { type: DT.DATE },
},
{ transaction: t }
);

await QI.addColumn('wallet', 'account_profile_id', {
type: DT.INTEGER,
references: {
model: 'account_profile',
key: 'id'
},
onUpdate: 'cascade',
onDelete: 'set null',
allowNull: true,
defaultValue: null
},
{transaction: t});

await QI.sequelize.query(`INSERT INTO public.account_profile ( actor, permission, is_default ) VALUES ('${defaultActor}', '${defaultPermission}', TRUE)`, {transaction: t});
await QI.sequelize.query(`INSERT INTO public.account_profile ( actor, permission ) SELECT actor, permission FROM public.wallet WHERE actor <> '' GROUP BY actor, permission;`, {transaction: t});
await QI.sequelize.query(`UPDATE public.wallet SET account_profile_id = public.account_profile.id FROM public.account_profile WHERE public.account_profile.actor = public.wallet.actor AND public.account_profile.permission = public.wallet.permission;`, {transaction: t});
await QI.sequelize.query(`UPDATE public.wallet SET account_profile_id = 1 WHERE public.wallet.account_profile_id IS NULL;`, {transaction: t});
await QI.removeColumn('wallet', 'actor', {transaction: t});
await QI.removeColumn('wallet', 'permission', {transaction: t});
});
},

down: async (QI, DT) => {
return QI.sequelize.transaction( async t => {
await QI.addColumn('wallet', 'actor', {
type: DT.STRING,
allowNull: false,
defaultValue: ''
}, {transaction: t});
await QI.addColumn('wallet', 'permission', {
type: DT.STRING,
allowNull: false,
defaultValue: ''
}, {transaction: t});

await QI.sequelize.query(`UPDATE public.wallet SET actor = public.account_profile.actor, permission = public.account_profile.permission FROM public.account_profile WHERE public.account_profile.id = public.wallet.account_profile_id;`, {transaction: t})

await QI.removeColumn('wallet', 'account_profile_id', {transaction: t});
return QI.dropTable('actor', {transaction: t});
})
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
'use strict';

const autoRetry = async QI => {
QI.sequelize.transaction( async t => {
const btes = await QI.sequelize.query(`SELECT account_id, type FROM "blockchain_trx" bt
JOIN blockchain_trx_event bte ON bte.blockchain_trx_id = bt.id
WHERE bte.id = (
SELECT max(sub_bte.id) over (partition by account_id) mid
FROM blockchain_trx sub_bt
LEFT OUTER JOIN blockchain_trx_event sub_bte ON sub_bte.blockchain_trx_id = sub_bt.id
WHERE sub_bte.created > '04-28-2022' AND sub_bt.account_id = bt.account_id
GROUP BY sub_bte.id, sub_bt.account_id, sub_bt.type
ORDER BY sub_bte.id DESC
LIMIT 1
)
AND bte.trx_status = 'review'
AND bte.trx_status_notes = 'Insufficient funds to cover fee'
AND bte.created > '04-28-2022'`
, { transaction: t });

const bts = []
const accountIdByBts = {}
for (const bteItem of btes[0]) {
const btRes = await QI.sequelize.query(`
INSERT INTO "blockchain_trx" (account_id, type) VALUES (${bteItem.account_id}, '${bteItem.type}') RETURNING id
`, { transaction: t });
bts.push(btRes[0][0].id)
accountIdByBts[btRes[0][0].id] = bteItem.account_id
}
for (const btId of bts) {
const bteRes = await QI.sequelize.query(`
INSERT INTO "blockchain_trx_event" (blockchain_trx_id, trx_status, trx_status_notes)
VALUES (${btId}, 'retry', 'Retry insufficient funds trx errors') RETURNING id
`, { transaction: t });

await QI.sequelize.query(`
UPDATE "registrations-search" SET blockchain_trx_id = ${btId},
blockchain_trx_event_id = ${bteRes[0][0].id},
trx_status = 'retry'
WHERE account_id = ${accountIdByBts[btId]}
`, { transaction: t });
}
});
}

module.exports = {
up: async QI => {
// Auto-retry Insufficient funds errored. No need to launch for now
// autoRetry(QI)
},

down: async () => {
//
}
};
40 changes: 40 additions & 0 deletions server/db/models/account_profile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const Sequelize = require('sequelize')

module.exports = (sequelize, DataTypes) => {
const AccountProfile = sequelize.define('AccountProfile', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
allowNull: false
},
actor: {
type: DataTypes.STRING,
allowNull: false,
},
permission: {
type: DataTypes.STRING,
allowNull: false
},
name: {
type: DataTypes.STRING,
allowNull: true
},
is_default: {
type: DataTypes.BOOLEAN,
allowNull: false,
defaultValue: false
},
}, {
tableName: 'account_profile',
paranoid: true,
timestamps: true,
underscored: true,
});

AccountProfile.associate = function(models) {
AccountProfile.hasMany(models.Wallet, { as: 'accountProfile', foreignKey: 'account_profile_id'})
};

return AccountProfile;
};
4 changes: 2 additions & 2 deletions server/db/models/blockchain-trx.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ module.exports = (sequelize, DataTypes) => {
type: {
type: DataTypes.STRING(30),
allowNull: false,
values: ['register', 'renew'],
values: ['register', 'renew', 'add_bundles'],
validate: {
isIn: [['register', 'renew']]
isIn: [['register', 'renew', 'add_bundles']]
},
comment: 'Primary reason for this transaction'
},
Expand Down
15 changes: 5 additions & 10 deletions server/db/models/wallet.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,6 @@ module.exports = (sequelize, DataTypes) => {
defaultValue: ['pending', 'retry', 'success', 'expire', 'review', 'cancel'],
comment: 'enabled webhook events'
},
actor: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ''
},
permission: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ''
},
api_enabled: {
type: DataTypes.BOOLEAN,
allowNull: false,
Expand All @@ -132,6 +122,10 @@ module.exports = (sequelize, DataTypes) => {
allowNull: true,
defaultValue: '',
comment: 'Disables limit registrations of free addresses for these IP addresses'
},
account_profile_id: {
type: DataTypes.INTEGER,
allowNull: true
}
}, {
tableName: 'wallet'
Expand All @@ -141,6 +135,7 @@ module.exports = (sequelize, DataTypes) => {
Wallet.hasMany(models.Account, {foreignKey: 'wallet_id'})
Wallet.hasMany(models.Notification, {foreignKey: 'wallet_id'})
Wallet.hasOne(models.WalletApi, { foreignKey: 'wallet_id', onDelete: 'CASCADE' })
Wallet.belongsTo(models.AccountProfile, { foreignKey: 'account_profile_id' });
};

return Wallet;
Expand Down
17 changes: 11 additions & 6 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,17 @@ app.use(handler(async function(req, res, next) {
}

// validate and re-parse prior server-state from the client
res.state = await AuthState({
stateString: req.get('state'),
stateHash: req.get('state-hash'),
bearer,
required
})
try {
res.state = await AuthState({
stateString: req.get('state'),
stateHash: req.get('state-hash'),
bearer,
required
})
} catch (e) {
return res.status(401).send({error: e.message || 'Unauthorized'})
}


// Server routes may modify this state
const send = res.send.bind(res)
Expand Down
5 changes: 3 additions & 2 deletions server/plugins/payment/coinbase/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,14 @@ class Coinbase {
*/
async createCharge({
name, logoUrl, price, type, address, publicKey,
accountId, redirectUrl
accountId, redirectUrl, isRegisterAction
}) {
const typeName = type === 'account' ? 'Account' : 'Domain'
const actionName = isRegisterAction ? 'Registration' : (type === 'account' ? 'Adding Bundles' : 'Renewing')

// @see https://commerce.coinbase.com/docs/api/#charges
const charge = {
name: `FIO ${typeName} Registration`,
name: `FIO ${typeName} ${actionName}`,
description: `Payment for ${address}`,
logo_url: logoUrl,
pricing_type: 'fixed_price',
Expand Down
Loading

0 comments on commit 9164479

Please sign in to comment.