Skip to content

Commit

Permalink
Create token api (#106)
Browse files Browse the repository at this point in the history
Signed-off-by: Kipkap <kipkap1001@gmail.com>
Signed-off-by: Kiran Pachhai <kiran@pachhai.com>
Co-authored-by: Kiran Pachhai <kiran@pachhai.com>
  • Loading branch information
himalayan-dev and kpachhai authored Feb 22, 2024
1 parent 982bd26 commit 12d668b
Show file tree
Hide file tree
Showing 25 changed files with 1,562 additions and 368 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
/*-
*
* Hedera Wallet Snap
*
* Copyright (C) 2024 Tuum Tech
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
import { FC, useContext, useRef, useState } from 'react';
import {
MetaMaskContext,
MetamaskActions,
} from '../../../contexts/MetamaskContext';
import useModal from '../../../hooks/useModal';
import { Account, CreateTokenRequestParams } from '../../../types/snap';
import { createToken, shouldDisplayReconnectButton } from '../../../utils';
import { Card, SendHelloButton } from '../../base';
import ExternalAccount, {
GetExternalAccountRef,
} from '../../sections/ExternalAccount';

type Props = {
network: string;
mirrorNodeUrl: string;
setAccountInfo: React.Dispatch<React.SetStateAction<Account>>;
};

const CreateToken: FC<Props> = ({ network, mirrorNodeUrl, setAccountInfo }) => {
const [state, dispatch] = useContext(MetaMaskContext);
const [loading, setLoading] = useState(false);
const { showModal } = useModal();
const [assetType, setAssetType] = useState<'TOKEN' | 'NFT'>('TOKEN');
const [tokenName, setTokenName] = useState('');
const [tokenSymbol, setTokenSymbol] = useState('');
const [tokenDecimals, setTokenDecimals] = useState(1);
const [initialSupply, setInitialSupply] = useState(100);
const [supplyPublicKey, setSupplyPublicKey] = useState('');

const externalAccountRef = useRef<GetExternalAccountRef>(null);

const handleCreateTokenClick = async () => {
setLoading(true);
try {
const externalAccountParams =
externalAccountRef.current?.handleGetAccountParams();

const createTokenParams = {
assetType,
name: tokenName,
symbol: tokenSymbol,
decimals: assetType === 'NFT' ? 0 : tokenDecimals,
supplyType: 'INFINITE',
initialSupply: assetType === 'NFT' ? 0 : initialSupply,
} as CreateTokenRequestParams;
if (assetType === 'NFT') {
createTokenParams.supplyPublicKey = supplyPublicKey;
}
const response: any = await createToken(
network,
mirrorNodeUrl,
createTokenParams,
externalAccountParams,
);

const { receipt, currentAccount } = response;

setAccountInfo(currentAccount);
console.log('receipt: ', receipt);

showModal({
title: 'Transaction Receipt',
content: JSON.stringify({ receipt }, null, 4),
});
} catch (e) {
console.error(e);
dispatch({ type: MetamaskActions.SetError, payload: e });
}
setLoading(false);
};

return (
<Card
content={{
title: 'createToken',
description: 'Create a token on Hedera using Hedera Token Service.',
form: (
<>
<ExternalAccount ref={externalAccountRef} />
<label>
Asset Type
<select
style={{ width: '100%' }}
value={assetType}
onChange={(e) =>
setAssetType(e.target.value as 'TOKEN' | 'NFT')
}
>
<option value="TOKEN">TOKEN</option>
<option value="NFT">NFT</option>
</select>
</label>
<br />

<label>
Enter the name for your token/NFT
<input
type="text"
style={{ width: '100%' }}
value={tokenName}
placeholder="Token Name"
onChange={(e) => setTokenName(e.target.value)}
/>
</label>
<br />

<label>
Enter the symbol for your token/NFT
<input
type="text"
style={{ width: '100%' }}
value={tokenSymbol}
placeholder="Token Symbol"
onChange={(e) => setTokenSymbol(e.target.value)}
/>
</label>
<br />

{assetType === 'TOKEN' && (
<>
<label>
Enter the decimals for your token
<input
type="number"
style={{ width: '100%' }}
value={tokenDecimals}
placeholder="Enter the number of decimals"
onChange={(e) =>
setTokenDecimals(parseFloat(e.target.value))
}
/>
</label>
<br />
<label>
Enter the initial supply for your token
<input
type="number"
style={{ width: '100%' }}
value={initialSupply}
placeholder="Enter the amount of initial supply"
onChange={(e) =>
setInitialSupply(parseFloat(e.target.value))
}
/>
</label>
<br />
</>
)}

{assetType === 'NFT' && (
<>
<label>
Enter the supply public key for your NFT
<input
type="text"
style={{ width: '100%' }}
value={supplyPublicKey}
placeholder="Enter the supply key"
onChange={(e) => setSupplyPublicKey(e.target.value)}
/>
</label>
<br />
</>
)}
</>
),
button: (
<SendHelloButton
buttonText="Create Token"
onClick={handleCreateTokenClick}
disabled={!state.installedSnap}
loading={loading}
/>
),
}}
disabled={!state.installedSnap}
fullWidth={
state.isFlask &&
Boolean(state.installedSnap) &&
!shouldDisplayReconnectButton(state.installedSnap)
}
/>
);
};

export { CreateToken };
7 changes: 7 additions & 0 deletions packages/hedera-wallet-snap/packages/site/src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import Tokens from '../components/cards/Tokens';
import { TransferCrypto } from '../components/cards/TransferCrypto';
import { UnstakeHbar } from '../components/cards/UnstakeHbar';
import { AssociateTokens } from '../components/cards/hts/AssociateTokens';
import { CreateToken } from '../components/cards/hts/CreateToken';
import { networkOptions } from '../config/constants';
import {
CardContainer,
Expand Down Expand Up @@ -211,6 +212,12 @@ const Index = () => {
setAccountInfo={setAccountInfo}
/>

<CreateToken
network={currentNetwork.value}
mirrorNodeUrl={mirrorNodeUrl}
setAccountInfo={setAccountInfo}
/>

<DeleteAccount
network={currentNetwork.value}
mirrorNodeUrl={mirrorNodeUrl}
Expand Down
37 changes: 33 additions & 4 deletions packages/hedera-wallet-snap/packages/site/src/types/snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,6 @@ export type GetTransactionsRequestParams = {
transactionId?: string;
};

export type AssociateTokensRequestParams = {
tokenIds: string[];
};

export type TransferCryptoRequestParams = {
transfers: SimpleTransfer[];
memo?: string;
Expand Down Expand Up @@ -118,6 +114,39 @@ export type DeleteAccountRequestParams = {
transferAccountId: string;
};

export type AssociateTokensRequestParams = {
tokenIds: string[];
};

export type TokenCustomFee = {
feeCollectorAccountId: string; // Sets the fee collector account ID that collects the fee
hbarAmount?: number; // Set the amount of HBAR to be collected
tokenAmount?: number; // Sets the amount of tokens to be collected as the fee
denominatingTokenId?: string; // The ID of the token used to charge the fee. The denomination of the fee is taken as HBAR if left unset
allCollectorsAreExempt?: boolean; // If true, exempts all the token's fee collector accounts from this fee
};

export type CreateTokenRequestParams = {
assetType: 'TOKEN' | 'NFT';
name: string;
symbol: string;
decimals: number;
initialSupply?: number;
kycPublicKey?: string;
freezePublicKey?: string;
pausePublicKey?: string;
wipePublicKey?: string;
supplyPublicKey?: string;
feeSchedulePublicKey?: string;
freezeDefault?: boolean;
expirationTime?: string;
autoRenewAccountId?: string;
tokenMemo?: string;
customFees?: TokenCustomFee[];
supplyType: 'FINITE' | 'INFINITE';
maxSupply?: number;
};

export type ExternalAccountParams = {
externalAccount: {
accountIdOrEvmAddress: string;
Expand Down
79 changes: 53 additions & 26 deletions packages/hedera-wallet-snap/packages/site/src/utils/snap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { ExternalAccountParams, GetSnapsResponse, Snap } from '../types';
import {
ApproveAllowanceRequestParams,
AssociateTokensRequestParams,
CreateTokenRequestParams,
DeleteAccountRequestParams,
DeleteAllowanceRequestParams,
GetAccountInfoRequestParams,
Expand Down Expand Up @@ -224,32 +225,6 @@ export const getTransactions = async (
});
};

/**
* Invoke the "associateTokens" method from the snap.
*/
export const associateTokens = async (
network: string,
mirrorNodeUrl: string,
associateTokensRequestParams: AssociateTokensRequestParams,
externalAccountparams?: ExternalAccountParams,
) => {
return await window.ethereum.request({
method: 'wallet_invokeSnap',
params: {
snapId: defaultSnapOrigin,
request: {
method: 'associateTokens',
params: {
network,
mirrorNodeUrl,
tokenIds: associateTokensRequestParams.tokenIds,
...externalAccountparams,
},
},
},
});
};

/**
* Invoke the "transferCrypto" method from the snap.
*/
Expand Down Expand Up @@ -416,4 +391,56 @@ export const deleteAccount = async (
});
};

/**
* Invoke the "associateTokens" method from the snap.
*/
export const associateTokens = async (
network: string,
mirrorNodeUrl: string,
associateTokensRequestParams: AssociateTokensRequestParams,
externalAccountparams?: ExternalAccountParams,
) => {
return await window.ethereum.request({
method: 'wallet_invokeSnap',
params: {
snapId: defaultSnapOrigin,
request: {
method: 'hts/associateTokens',
params: {
network,
mirrorNodeUrl,
tokenIds: associateTokensRequestParams.tokenIds,
...externalAccountparams,
},
},
},
});
};

/**
* Invoke the "createToken" method from the snap.
*/
export const createToken = async (
network: string,
mirrorNodeUrl: string,
createTokenRequestParams: CreateTokenRequestParams,
externalAccountparams?: ExternalAccountParams,
) => {
return await window.ethereum.request({
method: 'wallet_invokeSnap',
params: {
snapId: defaultSnapOrigin,
request: {
method: 'hts/createToken',
params: {
network,
mirrorNodeUrl,
...createTokenRequestParams,
...externalAccountparams,
},
},
},
});
};

export const isLocalSnap = (snapId: string) => snapId.startsWith('local:');
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "git+https://github.com/hashgraph/hedera-metamask-snaps.git"
},
"source": {
"shasum": "5d6XzqGIuaMBr8L8cWZVgT6GMftl95AzrNvYs8kG4+k=",
"shasum": "kA8SzTzH49ZRjOlMP9LpXm8EsIOG8fg3Gl67f6LhB0I=",
"location": {
"npm": {
"filePath": "dist/snap.js",
Expand Down
Loading

0 comments on commit 12d668b

Please sign in to comment.