diff --git a/package.json b/package.json index 015509d..ab82ace 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "dependencies": { "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", - "@solana/web3.js": "^0.71.5", + "@solana/web3.js": "^0.71.9", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", diff --git a/src/components/AddTokenDialog.js b/src/components/AddTokenDialog.js index a5ef317..8d762a1 100644 --- a/src/components/AddTokenDialog.js +++ b/src/components/AddTokenDialog.js @@ -45,7 +45,7 @@ export default function AddTokenDialog({ open, onClose }) { let wallet = useWallet(); let [tokenAccountCost] = useAsyncData( wallet.tokenAccountCost, - 'tokenAccountCost', + wallet.tokenAccountCost, ); let classes = useStyles(); let updateTokenName = useUpdateTokenName(); diff --git a/src/components/DebugButtons.js b/src/components/DebugButtons.js index 7083736..19c5018 100644 --- a/src/components/DebugButtons.js +++ b/src/components/DebugButtons.js @@ -49,12 +49,11 @@ export default function DebugButtons() { sendTransaction( createAndInitializeMint({ connection: wallet.connection, - payer: wallet.account, + owner: wallet.account, mint, amount: 1000, decimals: 2, initialAccount: new Account(), - mintOwner: wallet.account, }), { onSuccess: () => refreshWalletPublicKeys(wallet) }, ); diff --git a/src/utils/connection.js b/src/utils/connection.js index d130cfe..3d62598 100644 --- a/src/utils/connection.js +++ b/src/utils/connection.js @@ -12,7 +12,7 @@ export function ConnectionProvider({ children }) { clusterApiUrl('mainnet-beta'), ); - const connection = useMemo(() => new Connection(endpoint, 'single'), [ + const connection = useMemo(() => new Connection(endpoint, 'recent'), [ endpoint, ]); diff --git a/src/utils/tokens/data.js b/src/utils/tokens/data.js index f94b003..80d8fac 100644 --- a/src/utils/tokens/data.js +++ b/src/utils/tokens/data.js @@ -5,13 +5,13 @@ export const ACCOUNT_LAYOUT = BufferLayout.struct([ BufferLayout.blob(32, 'mint'), BufferLayout.blob(32, 'owner'), BufferLayout.nu64('amount'), - BufferLayout.blob(48), + BufferLayout.blob(93), ]); export const MINT_LAYOUT = BufferLayout.struct([ - BufferLayout.blob(36), + BufferLayout.blob(44), BufferLayout.u8('decimals'), - BufferLayout.blob(3), + BufferLayout.blob(37), ]); export function parseTokenAccountData(data) { diff --git a/src/utils/tokens/index.js b/src/utils/tokens/index.js index 66e0660..080bf74 100644 --- a/src/utils/tokens/index.js +++ b/src/utils/tokens/index.js @@ -2,6 +2,7 @@ import { PublicKey, SystemProgram, Transaction } from '@solana/web3.js'; import { initializeAccount, initializeMint, + mintTo, TOKEN_PROGRAM_ID, transfer, } from './instructions'; @@ -56,15 +57,14 @@ export async function getOwnedTokenAccounts(connection, publicKey) { export async function createAndInitializeMint({ connection, - payer, // Account for paying fees + owner, // Account for paying fees and allowed to mint new tokens mint, // Account to hold token information amount, // Number of tokens to issue decimals, initialAccount, // Account to hold newly issued tokens, if amount > 0 - mintOwner, // Optional account, allowed to mint tokens }) { let transaction = SystemProgram.createAccount({ - fromPubkey: payer.publicKey, + fromPubkey: owner.publicKey, newAccountPubkey: mint.publicKey, lamports: await connection.getMinimumBalanceForRentExemption( MINT_LAYOUT.span, @@ -72,11 +72,18 @@ export async function createAndInitializeMint({ space: MINT_LAYOUT.span, programId: TOKEN_PROGRAM_ID, }); - let signers = [payer, mint]; - if (amount) { + transaction.add( + initializeMint({ + mint: mint.publicKey, + decimals, + mintAuthority: owner.publicKey, + }), + ); + let signers = [owner, mint]; + if (amount > 0) { transaction.add( SystemProgram.createAccount({ - fromPubkey: payer.publicKey, + fromPubkey: owner.publicKey, newAccountPubkey: initialAccount.publicKey, lamports: await connection.getMinimumBalanceForRentExemption( ACCOUNT_LAYOUT.span, @@ -90,19 +97,18 @@ export async function createAndInitializeMint({ initializeAccount({ account: initialAccount.publicKey, mint: mint.publicKey, - owner: payer.publicKey, + owner: owner.publicKey, + }), + ); + transaction.add( + mintTo({ + mint: mint.publicKey, + destination: initialAccount.publicKey, + amount, + mintAuthority: owner.publicKey, }), ); } - transaction.add( - initializeMint({ - mint: mint.publicKey, - amount, - decimals, - initialAccount: initialAccount?.publicKey, - mintOwner: mintOwner.publicKey, - }), - ); return await connection.sendTransaction(transaction, signers); } diff --git a/src/utils/tokens/instructions.js b/src/utils/tokens/instructions.js index 364259b..abda04f 100644 --- a/src/utils/tokens/instructions.js +++ b/src/utils/tokens/instructions.js @@ -1,8 +1,12 @@ import * as BufferLayout from 'buffer-layout'; -import { PublicKey, TransactionInstruction } from '@solana/web3.js'; +import { + PublicKey, + SYSVAR_RENT_PUBKEY, + TransactionInstruction, +} from '@solana/web3.js'; export const TOKEN_PROGRAM_ID = new PublicKey( - 'TokenSVp5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o', + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', ); export const WRAPPED_SOL_MINT = new PublicKey( @@ -13,9 +17,10 @@ const LAYOUT = BufferLayout.union(BufferLayout.u8('instruction')); LAYOUT.addVariant( 0, BufferLayout.struct([ - // TODO: does this need to be aligned? - BufferLayout.nu64('amount'), BufferLayout.u8('decimals'), + BufferLayout.blob(32, 'mintAuthority'), + BufferLayout.u8('freezeAuthorityOption'), + BufferLayout.blob(32, 'freezeAuthority'), ]), 'initializeMint', ); @@ -48,24 +53,22 @@ function encodeTokenInstructionData(instruction) { export function initializeMint({ mint, - amount, decimals, - initialAccount, - mintOwner, + mintAuthority, + freezeAuthority, }) { - let keys = [{ pubkey: mint, isSigner: false, isWritable: true }]; - if (amount) { - keys.push({ pubkey: initialAccount, isSigner: false, isWritable: true }); - } - if (mintOwner) { - keys.push({ pubkey: mintOwner, isSigner: false, isWritable: false }); - } + let keys = [ + { pubkey: mint, isSigner: false, isWritable: true }, + { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, + ]; return new TransactionInstruction({ keys, data: encodeTokenInstructionData({ initializeMint: { - amount, decimals, + mintAuthority: mintAuthority.toBuffer(), + freezeAuthorityOption: !!freezeAuthority, + freezeAuthority: (freezeAuthority || new PublicKey()).toBuffer(), }, }), programId: TOKEN_PROGRAM_ID, @@ -77,6 +80,7 @@ export function initializeAccount({ account, mint, owner }) { { pubkey: account, isSigner: false, isWritable: true }, { pubkey: mint, isSigner: false, isWritable: false }, { pubkey: owner, isSigner: false, isWritable: false }, + { pubkey: SYSVAR_RENT_PUBKEY, isSigner: false, isWritable: false }, ]; return new TransactionInstruction({ keys, @@ -101,3 +105,20 @@ export function transfer({ source, destination, amount, owner }) { programId: TOKEN_PROGRAM_ID, }); } + +export function mintTo({ mint, destination, amount, mintAuthority }) { + let keys = [ + { pubkey: mint, isSigner: false, isWritable: true }, + { pubkey: destination, isSigner: false, isWritable: true }, + { pubkey: mintAuthority, isSigner: true, isWritable: false }, + ]; + return new TransactionInstruction({ + keys, + data: encodeTokenInstructionData({ + mintTo: { + amount, + }, + }), + programId: TOKEN_PROGRAM_ID, + }); +} diff --git a/yarn.lock b/yarn.lock index 4d25386..04d0581 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1119,7 +1119,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.11.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== @@ -1461,10 +1461,10 @@ resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" integrity sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw== -"@solana/web3.js@^0.71.5": - version "0.71.5" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-0.71.5.tgz#6ab98c18dad7cd36ffc76ee3c28ed1fccf8477d5" - integrity sha512-yh2hnSHuXBFggu4yJv0qaZwSyEfpsZJ7MqlSJH9hT1kB1T/QSpSP7TvxiMwTTC51k090HmORfAXvzXlN+hJg9A== +"@solana/web3.js@^0.71.9": + version "0.71.9" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-0.71.9.tgz#d9a5683a2697f4db42b7e4bdcf8b513e5db493e1" + integrity sha512-xn/6i3XwKA6RMKlVWxurKpJukHoJtiYm1W/r0cDVZYde7WHObm5F3W3bUjgO5K1lO0tHAEEf9/pyCpF6R73U0g== dependencies: "@babel/runtime" "^7.3.1" bn.js "^5.0.0" @@ -1477,7 +1477,7 @@ mz "^2.7.0" node-fetch "^2.2.0" npm-run-all "^4.1.5" - rpc-websockets "^5.0.8" + rpc-websockets "^7.1.0" superstruct "^0.8.3" tweetnacl "^1.0.0" ws "^7.0.0" @@ -2944,6 +2944,13 @@ buffer@^5.4.3: base64-js "^1.0.2" ieee754 "^1.1.4" +bufferutil@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7" + integrity sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA== + dependencies: + node-gyp-build "~3.7.0" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -4703,16 +4710,16 @@ etag@~1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= -eventemitter3@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== - eventemitter3@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== +eventemitter3@^4.0.6: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + events@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/events/-/events-3.2.0.tgz#93b87c18f8efcd4202a461aec4dfc0556b639379" @@ -7720,6 +7727,11 @@ neo-async@^2.5.0, neo-async@^2.6.1: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + next-tick@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" @@ -7748,6 +7760,11 @@ node-forge@0.9.0: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.0.tgz#d624050edbb44874adca12bb9a52ec63cb782579" integrity sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ== +node-gyp-build@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" + integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -9939,18 +9956,21 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rpc-websockets@^5.0.8: - version "5.3.1" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-5.3.1.tgz#678ca24315e4fe34a5f42ac7c2744764c056eb08" - integrity sha512-rIxEl1BbXRlIA9ON7EmY/2GUM7RLMy8zrUPTiLPFiYnYOz0I3PXfCmDDrge5vt4pW4oIcAXBDvgZuJ1jlY5+VA== +rpc-websockets@^7.1.0: + version "7.3.1" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.3.1.tgz#6519eca406d960f8ae1881874941d9fa05bf6728" + integrity sha512-7DhZirsTQv4UMS/9q9t3Urhb6kmh3iLyqIFeuhKmQtsmLP3fWrc2KyfoU5zuiBR7HP1IaNhEc3y8rL9SyCXqbw== dependencies: - "@babel/runtime" "^7.8.7" + "@babel/runtime" "^7.11.2" assert-args "^1.2.1" - babel-runtime "^6.26.0" circular-json "^0.5.9" - eventemitter3 "^3.1.2" - uuid "^3.4.0" - ws "^5.2.2" + eventemitter3 "^4.0.6" + next-tick "^1.1.0" + uuid "^8.3.0" + ws "^7.3.1" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" rsvp@^4.8.4: version "4.8.5" @@ -11254,6 +11274,13 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== +utf-8-validate@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.2.tgz#63cfbccd85dc1f2b66cf7a1d0eebc08ed056bfb3" + integrity sha512-SwV++i2gTD5qh2XqaPzBnNX88N6HdyhQrNNRykvcS0QKvItV9u3vPEJr+X5Hhfb1JC0r0e1alL0iB09rY8+nmw== + dependencies: + node-gyp-build "~3.7.0" + util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -11301,11 +11328,16 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= -uuid@^3.0.1, uuid@^3.2.1, uuid@^3.3.2, uuid@^3.4.0: +uuid@^3.0.1, uuid@^3.2.1, uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" + integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== + v8-compile-cache@^2.0.3: version "2.1.1" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" @@ -11778,7 +11810,7 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^5.2.0, ws@^5.2.2: +ws@^5.2.0: version "5.2.2" resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== @@ -11792,7 +11824,7 @@ ws@^6.1.2, ws@^6.2.1: dependencies: async-limiter "~1.0.0" -ws@^7.0.0: +ws@^7.0.0, ws@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==