diff --git a/README.md b/README.md index 96b56375..293fde6b 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,11 @@ This is the expected Private Key: This is the expected Public Key: "FIO5kJKNHwctcfUM5XZyiWSqSTM5HTzznJP9F3ZdbhaQAHEVq575o" +## Version 1.9.0 +### Breaking changes: +- Set new parameter `authPermission` for sign and push transactions +- `pushTransaction` receives object params instead of multiple arguments + ## Version 1.0.2 Bug Fix to method: addPublicAddresses - TechnologyProviderId (i.e. TPID), was not being set correctly for this method. diff --git a/documentation/classes/fiosdk.html b/documentation/classes/fiosdk.html index 37214e0c..385ca18e 100644 --- a/documentation/classes/fiosdk.html +++ b/documentation/classes/fiosdk.html @@ -1063,13 +1063,13 @@

Returns Promise

pushTransaction

Returns Promise<any>

diff --git a/lib/FIOSDK.js b/lib/FIOSDK.js index b828477f..38c261ab 100644 --- a/lib/FIOSDK.js +++ b/lib/FIOSDK.js @@ -949,11 +949,15 @@ class FIOSDK { const { fee: stakeFee } = yield this.getFee(EndPoint_1.EndPoint.stakeFioTokens, fioAddress); fee = stakeFee; } - return this.pushTransaction('fio.staking', 'stakefio', { - amount, - fio_address: fioAddress, - max_fee: fee, - tpid: technologyProviderId, + return this.pushTransaction({ + account: 'fio.staking', + action: 'stakefio', + data: { + amount, + fio_address: fioAddress, + max_fee: fee, + tpid: technologyProviderId, + }, }); }); } @@ -971,11 +975,15 @@ class FIOSDK { const { fee: stakeFee } = yield this.getFee(EndPoint_1.EndPoint.unStakeFioTokens, fioAddress); fee = stakeFee; } - return this.pushTransaction('fio.staking', 'unstakefio', { - amount, - fio_address: fioAddress, - max_fee: fee, - tpid: technologyProviderId, + return this.pushTransaction({ + account: 'fio.staking', + action: 'unstakefio', + data: { + amount, + fio_address: fioAddress, + max_fee: fee, + tpid: technologyProviderId, + }, }); }); } @@ -993,7 +1001,7 @@ class FIOSDK { * @param data JSON object with params for action * @param encryptOptions JSON object with params for encryption */ - pushTransaction(account, action, data, encryptOptions = {}) { + pushTransaction({ account, action, data, authPermission, encryptOptions = {}, signingAccount, }) { return __awaiter(this, void 0, void 0, function* () { data.tpid = this.getTechnologyProviderId(data.tpid); if (data.content && !encryptOptions.key) { @@ -1014,7 +1022,14 @@ class FIOSDK { // } } - const pushTransaction = new SignedTransactions.PushTransaction(action, account, data, encryptOptions); + const pushTransaction = new SignedTransactions.PushTransaction({ + action, + account, + authPermission, + data, + encryptOptions, + signingAccount, + }); return pushTransaction.execute(this.privateKey, this.publicKey, this.returnPreparedTrx); }); } @@ -1161,7 +1176,14 @@ class FIOSDK { case 'getMultiplier': return this.getMultiplier(); case 'pushTransaction': - return this.pushTransaction(params.account, params.action, params.data, params.encryptOptions); + return this.pushTransaction({ + account: params.account, + action: params.action, + data: params.data, + authPermission: params.authPermission, + encryptOptions: params.encryptOptions, + signingAccount: params.signingAccount, + }); case 'getAccountPubKey': return this.getAccountPubKey(params.account); case 'getEncryptKey': diff --git a/lib/transactions/Transactions.js b/lib/transactions/Transactions.js index 6f1d49bd..7ada2c87 100644 --- a/lib/transactions/Transactions.js +++ b/lib/transactions/Transactions.js @@ -169,7 +169,7 @@ class Transactions { textEncoder, }); } - createRawTransaction({ account, action, data, publicKey, chainData }) { + createRawTransaction({ account, action, authPermission, data, publicKey, chainData, signingAccount }) { return __awaiter(this, void 0, void 0, function* () { const rawTransaction = new RawTransaction_1.RawTransaction(); const rawaction = new RawAction_1.RawAction(); @@ -178,10 +178,11 @@ class Transactions { if (!data.actor) { data.actor = actor; } - rawaction.authorization.push(new Autorization_1.Autorization(data.actor, data.permission)); + rawaction.authorization.push(new Autorization_1.Autorization(data.actor, authPermission)); rawaction.account = account; rawaction.name = action; rawaction.data = data; + rawaction.actor = signingAccount; rawTransaction.actions.push(rawaction); if (chainData && chainData.ref_block_num) { this.setRawTransactionExp(rawTransaction, chainData); diff --git a/lib/transactions/signed/PushTransaction.js b/lib/transactions/signed/PushTransaction.js index c9826083..40fe93eb 100644 --- a/lib/transactions/signed/PushTransaction.js +++ b/lib/transactions/signed/PushTransaction.js @@ -4,7 +4,7 @@ exports.PushTransaction = void 0; const constants_1 = require("../../utils/constants"); const SignedTransaction_1 = require("./SignedTransaction"); class PushTransaction extends SignedTransaction_1.SignedTransaction { - constructor(action, account, data, encryptOptions = {}) { + constructor({ action, account, authPermission, data, encryptOptions = {}, signingAccount, }) { super(); this.ENDPOINT = 'chain/push_transaction'; this.ACTION = ''; @@ -15,13 +15,15 @@ class PushTransaction extends SignedTransaction_1.SignedTransaction { } this.data = data; this.encryptOptions = encryptOptions; + this.authPermission = authPermission; + this.signingAccount = signingAccount; } getData() { const data = Object.assign({}, this.data); if (data.content && this.encryptOptions && this.encryptOptions.key && this.encryptOptions.contentType) { data.content = this.getCipherContent(this.encryptOptions.contentType, data.content, this.privateKey, this.encryptOptions.key); } - return Object.assign(Object.assign({}, data), { actor: this.data.actor != null && this.data.actor !== '' ? this.data.actor : this.getActor(), permission: this.data.permission || 'active' }); + return Object.assign(Object.assign({}, data), { actor: this.data.actor != null && this.data.actor !== '' ? this.data.actor : this.getActor() }); } } exports.PushTransaction = PushTransaction; diff --git a/lib/transactions/signed/SignedTransaction.js b/lib/transactions/signed/SignedTransaction.js index b4a8cafd..c0baa7fb 100644 --- a/lib/transactions/signed/SignedTransaction.js +++ b/lib/transactions/signed/SignedTransaction.js @@ -38,7 +38,9 @@ class SignedTransaction extends Transactions_1.Transactions { const rawTransaction = yield this.createRawTransaction({ account: this.getAccount(), action: this.getAction(), + authPermission: this.getAuthPermission(), data: this.getData(), + signingAccount: this.getSigningAccount(), }); const result = yield this.pushToServer(rawTransaction, this.getEndPoint(), dryRun); return this.prepareResponse(result); @@ -53,6 +55,12 @@ class SignedTransaction extends Transactions_1.Transactions { getAccount() { return this.ACCOUNT; } + getAuthPermission() { + return this.authPermission; + } + getSigningAccount() { + return this.signingAccount; + } getEndPoint() { return this.ENDPOINT; } diff --git a/src/FIOSDK.ts b/src/FIOSDK.ts index af1373c2..8514fa55 100644 --- a/src/FIOSDK.ts +++ b/src/FIOSDK.ts @@ -1403,16 +1403,16 @@ export class FIOSDK { const { fee: stakeFee } = await this.getFee(EndPoint.stakeFioTokens, fioAddress) fee = stakeFee } - return this.pushTransaction( - 'fio.staking', - 'stakefio', - { + return this.pushTransaction({ + account: 'fio.staking', + action: 'stakefio', + data: { amount, fio_address: fioAddress, max_fee: fee, tpid: technologyProviderId, }, - ) + }) } /** @@ -1433,16 +1433,16 @@ export class FIOSDK { const { fee: stakeFee } = await this.getFee(EndPoint.unStakeFioTokens, fioAddress) fee = stakeFee } - return this.pushTransaction( - 'fio.staking', - 'unstakefio', - { + return this.pushTransaction({ + account: 'fio.staking', + action: 'unstakefio', + data: { amount, fio_address: fioAddress, max_fee: fee, tpid: technologyProviderId, }, - ) + }) } /** @@ -1460,12 +1460,21 @@ export class FIOSDK { * @param data JSON object with params for action * @param encryptOptions JSON object with params for encryption */ - public async pushTransaction( + public async pushTransaction({ + account, + action, + data, + authPermission, + encryptOptions = {}, + signingAccount, + }: { account: string, action: string, data: any, - encryptOptions: EncryptOptions = {}, - ): Promise { + authPermission?: string, + encryptOptions?: EncryptOptions, + signingAccount?: string, +}): Promise { data.tpid = this.getTechnologyProviderId(data.tpid) if (data.content && !encryptOptions.key) { switch (action) { @@ -1485,12 +1494,14 @@ export class FIOSDK { // } } - const pushTransaction = new SignedTransactions.PushTransaction( + const pushTransaction = new SignedTransactions.PushTransaction({ action, account, + authPermission, data, encryptOptions, - ) + signingAccount, +}) return pushTransaction.execute(this.privateKey, this.publicKey, this.returnPreparedTrx) } @@ -1774,7 +1785,14 @@ export class FIOSDK { case 'getMultiplier': return this.getMultiplier() case 'pushTransaction': - return this.pushTransaction(params.account, params.action, params.data, params.encryptOptions) + return this.pushTransaction({ + account: params.account, + action: params.action, + data: params.data, + authPermission: params.authPermission, + encryptOptions: params.encryptOptions, + signingAccount: params.signingAccount, + }) case 'getAccountPubKey': return this.getAccountPubKey(params.account) case 'getEncryptKey': diff --git a/src/entities/Autorization.ts b/src/entities/Autorization.ts index 61ff8032..10a47d90 100644 --- a/src/entities/Autorization.ts +++ b/src/entities/Autorization.ts @@ -1,6 +1,6 @@ export class Autorization { public actor: string - public permission: string + public permission?: string constructor(actor: string, permission = 'active') { this.actor = actor diff --git a/src/entities/RawAction.ts b/src/entities/RawAction.ts index 1f279fa3..d68ce86d 100644 --- a/src/entities/RawAction.ts +++ b/src/entities/RawAction.ts @@ -5,4 +5,5 @@ export class RawAction { public name: string = '' // 'transfer', public authorization: Autorization[] = new Array() public data: any + public actor: string | undefined } diff --git a/src/transactions/Transactions.ts b/src/transactions/Transactions.ts index 53bce89c..2d820ab8 100644 --- a/src/transactions/Transactions.ts +++ b/src/transactions/Transactions.ts @@ -92,6 +92,8 @@ export class Transactions { public validationRules: any | null = null public expirationOffset: number = Constants.defaultExpirationOffset + public authPermission: string | undefined + public signingAccount: string | undefined public getActor(publicKey: string = ''): string { return Transactions.FioProvider.accountHash((publicKey === '' || !publicKey) ? this.publicKey : publicKey) @@ -223,16 +225,18 @@ export class Transactions { } public async createRawTransaction( - { account, action, data, publicKey, chainData }: { + { account, action, authPermission, data, publicKey, chainData, signingAccount }: { account: string; action: string; - data: any, - publicKey?: string, + authPermission?: string; + data: any; + publicKey?: string; chainData?: { ref_block_num: number, ref_block_prefix: number, expiration: string, - } + }; + signingAccount?: string; }, ): Promise { const rawTransaction = new RawTransaction() @@ -244,10 +248,11 @@ export class Transactions { data.actor = actor } - rawaction.authorization.push(new Autorization(data.actor, data.permission)) + rawaction.authorization.push(new Autorization(data.actor, authPermission)) rawaction.account = account rawaction.name = action rawaction.data = data + rawaction.actor = signingAccount rawTransaction.actions.push(rawaction) if (chainData && chainData.ref_block_num) { diff --git a/src/transactions/signed/PushTransaction.ts b/src/transactions/signed/PushTransaction.ts index ebb5bcf7..f62bd6f0 100644 --- a/src/transactions/signed/PushTransaction.ts +++ b/src/transactions/signed/PushTransaction.ts @@ -10,18 +10,31 @@ export class PushTransaction extends SignedTransaction { public ACCOUNT: string = Constants.defaultAccount public data: any public encryptOptions: EncryptOptions + public authPermission: string | undefined + public signingAccount: string | undefined - constructor( + constructor({ + action, + account, + authPermission, + data, + encryptOptions = {}, + signingAccount, + }: { action: string, account: string, + authPermission: string | undefined, data: any, - encryptOptions: EncryptOptions = {}, - ) { + encryptOptions: EncryptOptions, + signingAccount: string | undefined, +}) { super() this.ACTION = action if (account) { this.ACCOUNT = account } this.data = data this.encryptOptions = encryptOptions + this.authPermission = authPermission + this.signingAccount = signingAccount } public getData(): any { @@ -38,7 +51,6 @@ export class PushTransaction extends SignedTransaction { return { ...data, actor: this.data.actor != null && this.data.actor !== '' ? this.data.actor : this.getActor(), - permission: this.data.permission || 'active', } } diff --git a/src/transactions/signed/SignedTransaction.ts b/src/transactions/signed/SignedTransaction.ts index 7679fd1e..e326ea36 100644 --- a/src/transactions/signed/SignedTransaction.ts +++ b/src/transactions/signed/SignedTransaction.ts @@ -43,6 +43,8 @@ export abstract class SignedTransaction extends Transactions { public abstract getData(): any + public static authPermission: string | undefined + public static signingAccount: string | undefined public static expirationOffset: number public async execute(privateKey: string, publicKey: string, dryRun = false, expirationOffset = Constants.defaultExpirationOffset): Promise { @@ -53,7 +55,9 @@ export abstract class SignedTransaction extends Transactions { const rawTransaction = await this.createRawTransaction({ account: this.getAccount(), action: this.getAction(), + authPermission: this.getAuthPermission(), data: this.getData(), + signingAccount: this.getSigningAccount(), }) const result = await this.pushToServer(rawTransaction, this.getEndPoint(), dryRun) @@ -72,6 +76,14 @@ export abstract class SignedTransaction extends Transactions { return this.ACCOUNT } + public getAuthPermission(): string | undefined { + return this.authPermission + } + + public getSigningAccount(): string | undefined { + return this.signingAccount + } + public getEndPoint(): string { return this.ENDPOINT } diff --git a/tests/index.spec.js b/tests/index.spec.js index 4b7bfce6..e0f1db3f 100644 --- a/tests/index.spec.js +++ b/tests/index.spec.js @@ -9,7 +9,13 @@ const fetchJson = async (uri, opts = {}) => { return fetch(uri, opts) } -let privateKey, publicKey, privateKey2, publicKey2, testFioAddressName, testFioAddressName2 +let privateKey, + publicKey, + privateKey2, + publicKey2, + testFioAddressName, + testFioAddressName2, + testFioDomainName const mnemonic = 'property follow talent guilt uncover someone gain powder urge slot taxi sketch' const mnemonic2 = 'round work clump little air glue lemon gravity shed charge assault orbit' @@ -792,6 +798,131 @@ describe('Testing generic actions', () => { // }) }) +describe('Test addaddress on account with permissions', () => { + const account1 = FIOSDK.accountHash(publicKey).accountnm; + const account2 = FIOSDK.accountHash(publicKey2).accountnm; + + const permissionName = 'addmyadd'; // Must be < 12 chars + + it(`user1 creates addmyadd permission and assigns to user2`, async () => { + try { + const authorization_object = { + threshold: 1, + accounts: [ + { + permission: { + actor: account2, + permission: 'active', + }, + weight: 1, + }, + ], + keys: [], + waits: [], + }; + + const result = await fioSdk.genericAction('pushTransaction', { + action: 'updateauth', + account: 'eosio', + actor: account1, + data: { + permission: permissionName, //addmyadd + parent: 'active', + max_fee: defaultFee, + auth: authorization_object, + account: account1, + }, + }); + + expect(result).to.have.all.keys( + 'transaction_id', + 'block_num', + 'block_time' + ); + expect(result.block_num).to.be.a('number'); + expect(result.transaction_id).to.be.a('string'); + } catch (e) { + console.log(e); + } + }); + + it(`user1 links regmyadd permission to regaddress`, async () => { + try { + const result = await fioSdk.genericAction('pushTransaction', { + action: 'linkauth', + account: 'eosio', + actor: account1, + data: { + account: account1, // the owner of the permission to be linked, this account will sign the transaction + code: 'fio.address', // the contract owner of the action to be linked + type: 'addaddress', // the action to be linked + requirement: permissionName, // the name of the custom permission (created by updateauth) + max_fee: defaultFee, + }, + }); + + expect(result).to.have.all.keys( + 'transaction_id', + 'block_num', + 'block_time' + ); + expect(result.block_num).to.be.a('number'); + expect(result.transaction_id).to.be.a('string'); + } catch (e) { + console.log(e); + } + }); + + it(`renewdomain for user1`, async () => { + try { + const result = await fioSdk.genericAction('pushTransaction', { + action: 'renewdomain', + account: 'fio.address', + authPermission: 'active', + data: { + fio_domain: testFioDomainName, + max_fee: defaultFee, + tpid: '', + actor: account1, + }, + }); + + expect(result.status).to.equal('OK'); + } catch (e) { + console.log(e); + } + }); + + it(`addaddress as user2`, async () => { + try { + const result = await fioSdk.genericAction('pushTransaction', { + action: 'addaddress', + account: 'fio.address', + signingAccount: account2, + authPermission: permissionName, + data: { + fio_address: testFioAddressName, + public_addresses: [ + { + chain_code: 'BCH', + token_code: 'BCH', + public_address: + 'bitcoincash:qzf8zha74ahdh9j0xnwlffdn0zuyaslx3c90q7n9g9', + }, + ], + max_fee: defaultFee, + tpid: '', + actor: account1, + }, + }); + + expect(result.status).to.equal('OK'); + } catch (e) { + console.log(e); + } + }); +}); + describe('Staking tests', () => { let stakedBalance = 0; const stakeAmount = FIOSDK.amountToSUF(5); diff --git a/tests/testnet.spec.js b/tests/testnet.spec.js index d026e713..b44d8311 100644 --- a/tests/testnet.spec.js +++ b/tests/testnet.spec.js @@ -17,7 +17,8 @@ let privateKey = '', privateKey2 = '', publicKey2 = '', testFioAddressName = '', - testFioAddressName2 = '' + testFioAddressName2 = '', + testFioDomainName = ''; /** * Public Testnet API nodes can be found at: https://github.com/fioprotocol/fio.mainnet @@ -700,6 +701,125 @@ describe('Testing generic actions', () => { // }); }) +describe('Test addaddress on account with permissions', () => { + const account1 = FIOSDK.accountHash(publicKey).accountnm; + const account2 = FIOSDK.accountHash(publicKey2).accountnm; + + const permissionName = 'addmyadd'; // Must be < 12 chars + + it(`user1 creates addmyadd permission and assigns to user2`, async () => { + try { + const authorization_object = { + threshold: 1, + accounts: [ + { + permission: { + actor: account2, + permission: 'active', + }, + weight: 1, + }, + ], + keys: [], + waits: [], + }; + + const result = await fioSdk.genericAction('pushTransaction', { + action: 'updateauth', + account: 'eosio', + actor: account1, + data: { + permission: permissionName, //addmyadd + parent: 'active', + max_fee: defaultFee, + auth: authorization_object, + account: account1, + }, + }); + + expect(result).to.have.all.keys('transaction_id', 'block_num', 'block_time') + expect(result.block_num).to.be.a('number') + expect(result.transaction_id).to.be.a('string') + } catch (e) { + console.log(e); + } + }); + + it(`user1 links regmyadd permission to regaddress`, async () => { + try { + const result = await fioSdk.genericAction('pushTransaction', { + action: 'linkauth', + account: 'eosio', + actor: account1, + data: { + account: account1, // the owner of the permission to be linked, this account will sign the transaction + code: 'fio.address', // the contract owner of the action to be linked + type: 'addaddress', // the action to be linked + requirement: permissionName, // the name of the custom permission (created by updateauth) + max_fee: defaultFee, + }, + }); + + expect(result).to.have.all.keys('transaction_id', 'block_num', 'block_time') + expect(result.block_num).to.be.a('number') + expect(result.transaction_id).to.be.a('string') + } catch (e) { + console.log(e); + } + }); + + it(`renewdomain for user1`, async () => { + try { + const result = await fioSdk.genericAction('pushTransaction', { + action: 'renewdomain', + account: 'fio.address', + authPermission: 'active', + data: { + fio_domain: testFioDomainName, + max_fee: defaultFee, + tpid: '', + actor: account1, + }, + }); + + expect(result.status).to.equal('OK'); + } catch (e) { + console.log(e); + } + }); + + /* todo uncomment when the permissions go live in test net + it(`addaddress as user2`, async () => { + try { + const result = await fioSdk.genericAction('pushTransaction', { + action: 'addaddress', + account: 'fio.address', + signingAccount: account2, + authPermission: permissionName, + data: { + fio_address: testFioAddressName, + public_addresses: [ + { + chain_code: 'BCH', + token_code: 'BCH', + public_address: + 'bitcoincash:qzf8zha74ahdh9j0xnwlffdn0zuyaslx3c90q7n9g9', + }, + ], + max_fee: defaultFee, + tpid: '', + actor: account1, + }, + }); + console.log('Result: ', result); + expect(result.status).to.equal('OK'); + } catch (e) { + console.log(e); + } + }); + */ +}); + /* todo uncomment when the permissions go live in test net describe('Testing Fio permissions', () => {