-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(web-components): allow custom signer instead of keplr
- Loading branch information
1 parent
7a70e1e
commit 2d4c3bc
Showing
8 changed files
with
337 additions
and
276 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
61 changes: 61 additions & 0 deletions
61
packages/web-components/src/wallet-connection/connectKeplr.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// @ts-check | ||
import { Registry } from '@cosmjs/proto-signing'; | ||
import { | ||
SigningStargateClient, | ||
AminoTypes, | ||
defaultRegistryTypes, | ||
createBankAminoConverters, | ||
createAuthzAminoConverters, | ||
} from '@cosmjs/stargate'; | ||
import { Errors } from '../errors.js'; | ||
import { agoricConverters, agoricRegistryTypes } from './signerOptions.js'; | ||
|
||
/** @typedef {import('@keplr-wallet/types').Keplr} Keplr */ | ||
|
||
/** | ||
* | ||
* @param {string} chainId | ||
* @param {string} rpc | ||
*/ | ||
export const connectKeplr = async (chainId, rpc) => { | ||
if (!('keplr' in window)) { | ||
throw Error(Errors.noKeplr); | ||
} | ||
/** @type {import('@keplr-wallet/types').Keplr} */ | ||
// @ts-expect-error cast (checked above) | ||
const keplr = window.keplr; | ||
|
||
await null; | ||
try { | ||
await keplr.enable(chainId); | ||
} catch { | ||
throw Error(Errors.enableKeplr); | ||
} | ||
|
||
// Until we have SIGN_MODE_TEXTUAL, | ||
// Use Amino because Direct results in ugly protobuf in the keplr UI. | ||
const offlineSigner = await keplr.getOfflineSignerOnlyAmino(chainId); | ||
console.debug('InteractiveSigner', { offlineSigner }); | ||
|
||
// Currently, Keplr extension manages only one address/public key pair. | ||
const [account] = await offlineSigner.getAccounts(); | ||
const { address } = account; | ||
|
||
const signingClient = await SigningStargateClient.connectWithSigner( | ||
rpc, | ||
offlineSigner, | ||
{ | ||
aminoTypes: new AminoTypes({ | ||
...agoricConverters, | ||
...createBankAminoConverters(), | ||
...createAuthzAminoConverters(), | ||
}), | ||
registry: new Registry([...defaultRegistryTypes, ...agoricRegistryTypes]), | ||
}, | ||
); | ||
|
||
return { | ||
address, | ||
client: signingClient, | ||
}; | ||
}; |
123 changes: 123 additions & 0 deletions
123
packages/web-components/src/wallet-connection/makeAgoricSigner.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// @ts-check | ||
import { fromBech32, toBase64 } from '@cosmjs/encoding'; | ||
import { assertIsDeliverTxSuccess } from '@cosmjs/stargate'; | ||
import { stableCurrency } from './chainInfo.js'; | ||
import { AgoricMsgs } from './signerOptions.js'; | ||
|
||
/** @typedef {import("@cosmjs/proto-signing").EncodeObject} EncodeObject */ | ||
/** @typedef {import("@cosmjs/stargate").AminoConverters} AminoConverters */ | ||
/** @typedef {import("@cosmjs/stargate").StdFee} StdFee */ | ||
/** @typedef {import('@keplr-wallet/types').ChainInfo} ChainInfo */ | ||
/** @typedef {import('@keplr-wallet/types').Keplr} Keplr */ | ||
/** @typedef {import('@cosmjs/stargate').SigningStargateClient} SigningStargateClient */ | ||
|
||
/** | ||
* @param {string} address | ||
* @returns {Uint8Array} | ||
*/ | ||
const toAccAddress = address => { | ||
return fromBech32(address).data; | ||
}; | ||
|
||
// XXX domain of @agoric/cosmic-proto | ||
/** | ||
* non-exhaustive list of powerFlags | ||
* | ||
* See also MsgProvision in golang/cosmos/proto/agoric/swingset/msgs.proto | ||
*/ | ||
const PowerFlags = { | ||
SMART_WALLET: 'SMART_WALLET', | ||
}; | ||
|
||
/** @typedef {{owner: string, spendAction: string}} WalletSpendAction */ | ||
|
||
/** | ||
* @returns {StdFee} | ||
*/ | ||
const zeroFee = () => { | ||
const { coinMinimalDenom: denom } = stableCurrency; | ||
const fee = { | ||
amount: [{ amount: '0', denom }], | ||
gas: '300000', // TODO: estimate gas? | ||
}; | ||
return fee; | ||
}; | ||
|
||
/** | ||
* Use a signing client to | ||
* @param {SigningStargateClient} signingClient | ||
* @param {string} address | ||
* Ref: https://docs.keplr.app/api/ | ||
*/ | ||
export const makeAgoricSigner = (signingClient, address) => { | ||
const fee = zeroFee(); | ||
|
||
return harden({ | ||
/** | ||
* Sign and broadcast Provision for a new smart wallet | ||
* | ||
* @throws if account does not exist on chain, user cancels, | ||
* RPC connection fails, RPC service fails to broadcast ( | ||
* for example, if signature verification fails) | ||
*/ | ||
provisionSmartWallet: async () => { | ||
const { accountNumber, sequence } = await signingClient.getSequence( | ||
address, | ||
); | ||
console.log({ accountNumber, sequence }); | ||
|
||
const b64address = toBase64(toAccAddress(address)); | ||
|
||
const act1 = { | ||
typeUrl: AgoricMsgs.MsgProvision.typeUrl, | ||
value: { | ||
address: b64address, | ||
nickname: 'my wallet', | ||
powerFlags: [PowerFlags.SMART_WALLET], | ||
submitter: b64address, | ||
}, | ||
}; | ||
|
||
const msgs = [act1]; | ||
console.log('sign provision', { address, msgs, fee }); | ||
|
||
const tx = await signingClient.signAndBroadcast(address, msgs, fee); | ||
console.log('spend action result tx', tx); | ||
assertIsDeliverTxSuccess(tx); | ||
|
||
return tx; | ||
}, | ||
|
||
/** | ||
* Sign and broadcast WalletSpendAction | ||
* | ||
* @param {string} spendAction marshaled offer | ||
* @throws if account does not exist on chain, user cancels, | ||
* RPC connection fails, RPC service fails to broadcast ( | ||
* for example, if signature verification fails) | ||
*/ | ||
submitSpendAction: async spendAction => { | ||
const { accountNumber, sequence } = await signingClient.getSequence( | ||
address, | ||
); | ||
console.debug({ accountNumber, sequence }); | ||
|
||
const act1 = { | ||
typeUrl: AgoricMsgs.MsgWalletSpendAction.typeUrl, | ||
value: { | ||
owner: toBase64(toAccAddress(address)), | ||
spendAction, | ||
}, | ||
}; | ||
|
||
const msgs = [act1]; | ||
console.debug('sign spend action', { address, msgs, fee }); | ||
|
||
const tx = await signingClient.signAndBroadcast(address, msgs, fee); | ||
console.debug('spend action result tx', tx); | ||
assertIsDeliverTxSuccess(tx); | ||
|
||
return tx; | ||
}, | ||
}); | ||
}; |
Oops, something went wrong.