Skip to content

Commit

Permalink
chore: implemented account creation
Browse files Browse the repository at this point in the history
  • Loading branch information
dafuga committed Jul 26, 2024
1 parent 3aadea6 commit 521a9d2
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 8 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"prepare": "make"
},
"dependencies": {
"tslib": "^2.1.0"
"tslib": "^2.1.0",
"@greymass/create-account": "^1.0.2"
},
"peerDependencies": {
"@wharfkit/session": "^1.0.0"
Expand Down
60 changes: 53 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import {AccountCreator} from '@greymass/create-account'
import {
AbstractAccountCreationPlugin,
AccountCreationPlugin,
AccountCreationPluginConfig,
CreateAccountResponse,
Chains,
CreateAccountContext,
Checksum256Type,
PublicKey,
} from '@wharfkit/session'
import {AccountCreationPluginMetadata} from '@wharfkit/session'

export class AccountCreationPluginTEMPLATE
export class AccountCreationPluginMetamask
extends AbstractAccountCreationPlugin
implements AccountCreationPlugin
{
Expand Down Expand Up @@ -53,13 +56,56 @@ export class AccountCreationPluginTEMPLATE
* @param options CreateAccountContext
* @returns Promise<CreateAccountResponse>
*/
// TODO: Remove these eslint rule modifiers when you are implementing this method.
/* eslint-disable @typescript-eslint/no-unused-vars */
async create(context: CreateAccountContext): Promise<CreateAccountResponse> {
// Example response...
async create(context: CreateAccountContext) {
// Changed to arrow function
const qs = new URLSearchParams()
qs.set('supported_chains', String(context.chain))
if (context.appName) {
qs.set('scope', String(context.appName))
}

const ownerKey = await this.retrievePublicKey(context.chain.id, 0)

qs.set('owner_key', String(ownerKey))
qs.set('active_key', String(activeKey))
const accountCreator = new AccountCreator({
supportedChains: [String(chain.id)],
fullCreationServiceUrl: `${ACCOUNT_CREATION_SERVICE_URL}?${qs.toString()}`,
scope: context.appName || 'Antelope App',
})
const accountCreationResponse = await accountCreator.createAccount()

return {
chain: Chains.EOS,
accountName: 'wharfkit1111',
accountName: accountCreationResponse.sa,
chain: accountCreationResponse.sp,
}
}

async initialize() {
if (!this.provider) {
this.provider = await getSnapsProvider()
}
if (this.provider && !this.installedSnap) {
this.isFlask = await checkIsFlask(this.provider)
await this.setSnap()
if (!this.installedSnap) {
await this.requestSnap()
if (this.installedSnap) {
await this.initialize()
}
}
}
}

async retrievePublicKey(chainId: Checksum256Type, addressIndex = 0): Promise<PublicKey> {
await this.initialize()
if (!this.provider) {
throw new Error('Metamask not found')
}
const result = (await this.invokeSnap({
method: 'antelope_getPublicKey',
params: {chainId: String(chainId), addressIndex},
})) as string
return PublicKey.from(result)
}
}
132 changes: 132 additions & 0 deletions src/metamask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import type {EIP6963AnnounceProviderEvent, MetaMaskInpageProvider} from '@metamask/providers'

export type Snap = {
permissionName: string
id: string
version: string
initialPermissions: Record<string, unknown>
}

export type InvokeSnapParams = {
method: string
params?: Record<string, unknown>
}

/**
* Check if the current provider supports snaps by calling `wallet_getSnaps`.
*
* @param provider - The provider to use to check for snaps support. Defaults to
* `window.ethereum`.
* @returns True if the provider supports snaps, false otherwise.
*/
export async function hasSnapsSupport(provider: MetaMaskInpageProvider = window.ethereum) {
try {
await provider.request({
method: 'wallet_getSnaps',
})

return true
} catch {
return false
}
}

/**
* Get a MetaMask provider using EIP6963. This will return the first provider
* reporting as MetaMask. If no provider is found after 500ms, this will
* return null instead.
*
* @returns A MetaMask provider if found, otherwise null.
*/
export async function getMetaMaskEIP6963Provider() {
return new Promise<MetaMaskInpageProvider | null>((rawResolve) => {
// Timeout looking for providers after 500ms
const timeout = setTimeout(() => {
resolve(null)
}, 500)

/**
* Resolve the promise with a MetaMask provider and clean up.
*
* @param provider - A MetaMask provider if found, otherwise null.
*/
function resolve(provider: MetaMaskInpageProvider | null) {
window.removeEventListener('eip6963:announceProvider', onAnnounceProvider)
clearTimeout(timeout)
rawResolve(provider)
}

/**
* Listener for the EIP6963 announceProvider event.
*
* Resolves the promise if a MetaMask provider is found.
*
* @param event - The EIP6963 announceProvider event.
* @param event.detail - The details of the EIP6963 announceProvider event.
*/
function onAnnounceProvider({detail}: EIP6963AnnounceProviderEvent) {
const {info, provider} = detail

if (info.rdns.includes('io.metamask')) {
resolve(provider)
}
}

window.addEventListener('eip6963:announceProvider', onAnnounceProvider)

window.dispatchEvent(new Event('eip6963:requestProvider'))
})
}

/**
* Get a provider that supports snaps. This will loop through all the detected
* providers and return the first one that supports snaps.
*
* @returns The provider, or `null` if no provider supports snaps.
*/
export async function getSnapsProvider() {
if (typeof window === 'undefined') {
return null
}

if (await hasSnapsSupport()) {
return window.ethereum
}

if (window.ethereum?.detected) {
for (const provider of window.ethereum.detected) {
if (await hasSnapsSupport(provider)) {
return provider
}
}
}

if (window.ethereum?.providers) {
for (const provider of window.ethereum.providers) {
if (await hasSnapsSupport(provider)) {
return provider
}
}
}

const eip6963Provider = await getMetaMaskEIP6963Provider()

if (eip6963Provider && (await hasSnapsSupport(eip6963Provider))) {
return eip6963Provider
}

return null
}

/**
* Check if the current provider is a Flask provider by checking the client version.
*
* @param provider - The provider to use to check for Flask. Defaults to
* `window.ethereum`.
* @returns True if the provider is a Flask provider, false otherwise.
*/
export async function checkIsFlask(provider: MetaMaskInpageProvider | null) {
if (!provider) return false
const clientVersion = await provider.request({method: 'web3_clientVersion'})
return (clientVersion as string[])?.includes('flask')
}
17 changes: 17 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,23 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.53.0.tgz#bea56f2ed2b5baea164348ff4d5a879f6f81f20d"
integrity sha512-Kn7K8dx/5U6+cT1yEhpX1w4PCSg0M+XyRILPgvwcEBjerFWCwQj5sbr3/VmxqV0JGHCBCzyd6LxypEuehypY1w==

"@greymass/create-account@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@greymass/create-account/-/create-account-1.0.2.tgz#f2c3711018c9b8544e12695e1d9afb0e595170a1"
integrity sha512-YDtdQTEsMEaQHu5QJx+UzEsag/2yjHxHGPUVaGuNY5tL4p918VJMc0IskjwL4WCSWoRyWeWa4ZUGDz/KTE/Q9Q==
dependencies:
"@greymass/return-path" "^0.0.1"
"@wharfkit/antelope" "^0.7.3"
"@wharfkit/signing-request" "^3.0.0"
tslib "^2.1.0"

"@greymass/return-path@^0.0.1":
version "0.0.1"
resolved "https://registry.yarnpkg.com/@greymass/return-path/-/return-path-0.0.1.tgz#bcf4e74671af06d22ecd95dcdadb94efaa5adf78"
integrity sha512-PMPgSJYSHeaYXbURj4JfsEeReWkJqlTKFMn2iTPhvb+6ICR5GhVPDJKewqZPqpZumcD13M1c701YYWKHZlMsxw==
dependencies:
tslib "^2.1.0"

"@humanwhocodes/config-array@^0.11.13":
version "0.11.13"
resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.13.tgz#075dc9684f40a531d9b26b0822153c1e832ee297"
Expand Down

0 comments on commit 521a9d2

Please sign in to comment.