Skip to content

Commit

Permalink
feat(aepp): support external accounts in onAccount
Browse files Browse the repository at this point in the history
  • Loading branch information
davidyuk committed Apr 8, 2022
1 parent 48fe1fd commit 9745c73
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 52 deletions.
59 changes: 59 additions & 0 deletions src/account/rpc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/**
* AccountRpc module
* @module @aeternity/aepp-sdk/es/account/rpc
* @export AccountRpc
*/
import AccountBase from './base'
import { METHODS } from '../utils/aepp-wallet-communication/schema'
import { NotImplementedError } from '../utils/errors'

/**
* Account provided by wallet
* @alias module:@aeternity/aepp-sdk/es/account/rpc
* @function
* @rtype Stamp
* @param {Object} param Init params object
* @param {Object} param.rpcClient RpcClient instance
* @param {Object} param.address RPC account address
* @return {Object} AccountRpc instance
*/
export default AccountBase.compose({
init ({ rpcClient, address }) {
this._rpcClient = rpcClient
this._address = address
},
methods: {
sign () {
throw new NotImplementedError('RAW signing using wallet')
},
async address () {
return this._address
},
/**
* @function signTransaction
* @instance
* @rtype (tx: String, options = {}) => Promise
* @return {Promise<String>} Signed transaction
*/
async signTransaction (tx, options) {
return this._rpcClient.request(METHODS.sign, {
...options,
onAccount: this._address,
tx,
returnSigned: true,
networkId: this.getNetworkId(options)
})
},
/**
* @function signMessage
* @instance
* @rtype (message: String, options = {}) => Promise
* @return {Promise<String>} Signed message
*/
async signMessage (message, options) {
return this._rpcClient.request(
METHODS.signMessage, { ...options, onAccount: this._address, message }
)
}
}
})
63 changes: 19 additions & 44 deletions src/utils/aepp-wallet-communication/rpc/aepp-rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
* from '@aeternity/aepp-sdk/es/utils/aepp-wallet-communication/rpc/aepp-rpc'
*/
import { v4 as uuid } from '@aeternity/uuid'
import Ae from '../../../ae'
import AccountResolver from '../../../account/resolver'
import AccountRpc from '../../../account/rpc'
import { decode } from '../../encoder'
import RpcClient from './rpc-client'
import { getHandler, message } from '../helpers'
import { METHODS, RPC_STATUS, VERSION } from '../schema'
Expand Down Expand Up @@ -100,7 +102,7 @@ const handleMessage = (instance) => async (msg) => {
* @param {Object} connection Wallet connection object
* @return {Object}
*/
export default Ae.compose({
export default AccountResolver.compose({
async init ({
name,
connection,
Expand All @@ -117,14 +119,25 @@ export default Ae.compose({
this.name = name
this.debug = debug

const resolveAccountBase = this._resolveAccount
this._resolveAccount = (account = this.rpcClient?.currentAccount) => {
if (typeof account === 'string') {
decode(account, 'ak')
if (!this.rpcClient?.hasAccessToAccount(account)) {
throw new UnAuthorizedAccountError(account)
}
account = AccountRpc({ rpcClient: this.rpcClient, address: account })
}
if (!account) this._ensureAccountAccess()
return resolveAccountBase(account)
}

if (connection) {
// Init RPCClient
await this.connectToWallet(connection)
}
},
methods: {
sign () {
},
addresses () {
this._ensureAccountAccess()
return [this.rpcClient.currentAccount, ...Object.keys(this.rpcClient.accounts.connected)]
Expand Down Expand Up @@ -173,11 +186,6 @@ export default Ae.compose({
this.rpcClient.disconnect()
this.rpcClient = null
},
async address ({ onAccount } = {}) {
this._ensureConnected()
this._ensureAccountAccess(onAccount)
return onAccount ?? this.rpcClient.currentAccount
},
/**
* Ask address from wallet
* @function askAddresses
Expand All @@ -186,7 +194,6 @@ export default Ae.compose({
* @return {Promise} Address from wallet
*/
async askAddresses () {
this._ensureConnected()
this._ensureAccountAccess()
return this.rpcClient.request(METHODS.address)
},
Expand All @@ -203,35 +210,6 @@ export default Ae.compose({
this._ensureConnected()
return this.rpcClient.request(METHODS.subscribeAddress, { type, value })
},
/**
* Overwriting of `signTransaction` AE method
* All sdk API which use it will be send notification to wallet and wait for callBack
* @function signTransaction
* @instance
* @rtype (tx: String, options = {}) => Promise
* @return {Promise<String>} Signed transaction
*/
async signTransaction (tx, opt = {}) {
this._ensureConnected()
this._ensureAccountAccess(opt.onAccount)
return this.rpcClient.request(
METHODS.sign,
{ ...opt, tx, returnSigned: true, networkId: this.getNetworkId() }
)
},
/**
* Overwriting of `signMessage` AE method
* All sdk API which use it will be send notification to wallet and wait for callBack
* @function signMessage
* @instance
* @rtype (msg: String, options = {}) => Promise
* @return {Promise<String>} Signed transaction
*/
async signMessage (msg, opt = {}) {
this._ensureConnected()
this._ensureAccountAccess(opt.onAccount)
return this.rpcClient.request(METHODS.signMessage, { ...opt, message: msg })
},
/**
* Send connection request to wallet
* @function sendConnectRequest
Expand All @@ -254,11 +232,8 @@ export default Ae.compose({
if (this.rpcClient?.isConnected()) return
throw new NoWalletConnectedError('You are not connected to Wallet')
},
_ensureAccountAccess (onAccount) {
if (onAccount) {
if (this.rpcClient?.hasAccessToAccount(onAccount)) return
throw new UnAuthorizedAccountError(onAccount)
}
_ensureAccountAccess () {
this._ensureConnected()
if (this.rpcClient?.currentAccount) return
throw new UnsubscribedAccountError()
}
Expand Down
2 changes: 1 addition & 1 deletion test/integration/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const BaseAe = async (params = {}, compose = {}) => Universal
nodes: [{ name: 'test', instance: await Node({ url, internalUrl, ignoreVersion }) }]
})

const spendPromise = (async () => {
export const spendPromise = (async () => {
const ae = await BaseAe({ networkId, withoutGenesisAccount: false })
await ae.awaitHeight(2)
await ae.spend(1e26, account.publicKey)
Expand Down
19 changes: 12 additions & 7 deletions test/integration/rpc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import BrowserWindowMessageConnection from '../../src/utils/aepp-wallet-communic
import { getBrowserAPI, getHandler } from '../../src/utils/aepp-wallet-communication/helpers'
import { METHODS, RPC_STATUS } from '../../src/utils/aepp-wallet-communication/schema'
import { generateKeyPair, verify, hash } from '../../src/utils/crypto'
import { compilerUrl, genesisAccount, internalUrl, networkId, publicKey, url, ignoreVersion } from './'
import { compilerUrl, account, internalUrl, networkId, url, ignoreVersion, spendPromise } from './'
import {
NoBrowserFoundError,
NoWalletConnectedError,
Expand Down Expand Up @@ -62,9 +62,10 @@ describe('Aepp<->Wallet', function () {
let wallet

before(async () => {
await spendPromise
wallet = await RpcWallet({
compilerUrl,
accounts: [genesisAccount],
accounts: [MemoryAccount({ keypair: account })],
nodes: [{ name: 'local', instance: node }],
name: 'Wallet',
onConnection (aepp, { accept, deny }) {
Expand Down Expand Up @@ -185,7 +186,7 @@ describe('Aepp<->Wallet', function () {
subscriptionResponse.subscription.should.be.an('array')
subscriptionResponse.subscription.filter(e => e === 'connected').length.should.be.equal(1)
subscriptionResponse.address.current.should.be.an('object')
Object.keys(subscriptionResponse.address.current)[0].should.be.equal(publicKey)
Object.keys(subscriptionResponse.address.current)[0].should.be.equal(account.publicKey)
subscriptionResponse.address.connected.should.be.an('object')
Object.keys(subscriptionResponse.address.connected).length.should.be.equal(1)
})
Expand All @@ -196,8 +197,12 @@ describe('Aepp<->Wallet', function () {
.to.be.rejectedWith(UnAuthorizedAccountError, `You do not have access to account ${publicKey}`)
})

it('aepp accepts key pairs in onAccount', async () => {
await aepp.spend(100, await aepp.address(), { onAccount: account })
})

it('Get address: subscribed for accounts', async () => {
(await aepp.address()).should.be.equal(publicKey)
(await aepp.address()).should.be.equal(account.publicKey)
})

it('Ask for address: subscribed for accounts -> wallet deny', async () => {
Expand All @@ -214,7 +219,7 @@ describe('Aepp<->Wallet', function () {
}
const addressees = await aepp.askAddresses()
addressees.length.should.be.equal(2)
addressees[0].should.be.equal(publicKey)
addressees[0].should.be.equal(account.publicKey)
})

it('Not authorize', async () => {
Expand Down Expand Up @@ -533,7 +538,7 @@ describe('Aepp<->Wallet', function () {
before(async () => {
wallet = await RpcWallet({
compilerUrl,
accounts: [genesisAccount],
accounts: [MemoryAccount({ keypair: account })],
nodes: [{ name: 'local', instance: node }],
name: 'Wallet',
onConnection (aepp, { accept, deny }) {
Expand Down Expand Up @@ -584,7 +589,7 @@ describe('Aepp<->Wallet', function () {
subscriptionResponse.subscription.should.be.an('array')
subscriptionResponse.subscription.filter(e => e === 'connected').length.should.be.equal(1)
subscriptionResponse.address.current.should.be.an('object')
Object.keys(subscriptionResponse.address.current)[0].should.be.equal(publicKey)
Object.keys(subscriptionResponse.address.current)[0].should.be.equal(account.publicKey)
subscriptionResponse.address.connected.should.be.an('object')
Object.keys(subscriptionResponse.address.connected).length.should.be.equal(1)
})
Expand Down

0 comments on commit 9745c73

Please sign in to comment.