spl_token.sol 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // SPDX-License-Identifier: Apache-2.0
  2. // Disclaimer: This library provides a way for Solidity to interact with Solana's SPL-Token. Although it is production ready,
  3. // it has not been audited for security, so use it at your own risk.
  4. import 'solana';
  5. library SplToken {
  6. address constant tokenProgramId = address"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
  7. enum TokenInstruction {
  8. InitializeMint, // 0
  9. InitializeAccount, // 1
  10. InitializeMultisig, // 2
  11. Transfer, // 3
  12. Approve, // 4
  13. Revoke, // 5
  14. SetAuthority, // 6
  15. MintTo, // 7
  16. Burn, // 8
  17. CloseAccount, // 9
  18. FreezeAccount, // 10
  19. ThawAccount, // 11
  20. TransferChecked, // 12
  21. ApproveChecked, // 13
  22. MintToChecked, // 14
  23. BurnChecked, // 15
  24. InitializeAccount2, // 16
  25. SyncNative, // 17
  26. InitializeAccount3, // 18
  27. InitializeMultisig2, // 19
  28. InitializeMint2, // 20
  29. GetAccountDataSize, // 21
  30. InitializeImmutableOwner, // 22
  31. AmountToUiAmount, // 23
  32. UiAmountToAmount, // 24
  33. InitializeMintCloseAuthority, // 25
  34. TransferFeeExtension, // 26
  35. ConfidentialTransferExtension, // 27
  36. DefaultAccountStateExtension, // 28
  37. Reallocate, // 29
  38. MemoTransferExtension, // 30
  39. CreateNativeMint // 31
  40. }
  41. /// Mint new tokens. The transaction should be signed by the mint authority keypair
  42. ///
  43. /// @param mint the account of the mint
  44. /// @param account the token account where the minted tokens should go
  45. /// @param authority the public key of the mint authority
  46. /// @param amount the amount of tokens to mint
  47. function mint_to(address mint, address account, address authority, uint64 amount) internal {
  48. bytes instr = new bytes(9);
  49. instr[0] = uint8(TokenInstruction.MintTo);
  50. instr.writeUint64LE(amount, 1);
  51. AccountMeta[3] metas = [
  52. AccountMeta({pubkey: mint, is_writable: true, is_signer: false}),
  53. AccountMeta({pubkey: account, is_writable: true, is_signer: false}),
  54. AccountMeta({pubkey: authority, is_writable: false, is_signer: true})
  55. ];
  56. tokenProgramId.call{accounts: metas}(instr);
  57. }
  58. /// Transfer @amount token from @from to @to. The transaction should be signed by the owner
  59. /// keypair of the from account.
  60. ///
  61. /// @param from the account to transfer tokens from
  62. /// @param to the account to transfer tokens to
  63. /// @param owner the publickey of the from account owner keypair
  64. /// @param amount the amount to transfer
  65. function transfer(address from, address to, address owner, uint64 amount) internal {
  66. bytes instr = new bytes(9);
  67. instr[0] = uint8(TokenInstruction.Transfer);
  68. instr.writeUint64LE(amount, 1);
  69. AccountMeta[3] metas = [
  70. AccountMeta({pubkey: from, is_writable: true, is_signer: false}),
  71. AccountMeta({pubkey: to, is_writable: true, is_signer: false}),
  72. AccountMeta({pubkey: owner, is_writable: false, is_signer: true})
  73. ];
  74. tokenProgramId.call{accounts: metas}(instr);
  75. }
  76. /// Burn @amount tokens in account. This transaction should be signed by the owner.
  77. ///
  78. /// @param account the acount for which tokens should be burned
  79. /// @param mint the mint for this token
  80. /// @param owner the publickey of the account owner keypair
  81. /// @param amount the amount to burn
  82. function burn(address account, address mint, address owner, uint64 amount) internal {
  83. bytes instr = new bytes(9);
  84. instr[0] = uint8(TokenInstruction.Burn);
  85. instr.writeUint64LE(amount, 1);
  86. AccountMeta[3] metas = [
  87. AccountMeta({pubkey: account, is_writable: true, is_signer: false}),
  88. AccountMeta({pubkey: mint, is_writable: true, is_signer: false}),
  89. AccountMeta({pubkey: owner, is_writable: false, is_signer: true})
  90. ];
  91. tokenProgramId.call{accounts: metas}(instr);
  92. }
  93. /// Approve an amount to a delegate. This transaction should be signed by the owner
  94. ///
  95. /// @param account the account for which a delegate should be approved
  96. /// @param delegate the delegate publickey
  97. /// @param owner the publickey of the account owner keypair
  98. /// @param amount the amount to approve
  99. function approve(address account, address delegate, address owner, uint64 amount) internal {
  100. bytes instr = new bytes(9);
  101. instr[0] = uint8(TokenInstruction.Approve);
  102. instr.writeUint64LE(amount, 1);
  103. AccountMeta[3] metas = [
  104. AccountMeta({pubkey: account, is_writable: true, is_signer: false}),
  105. AccountMeta({pubkey: delegate, is_writable: false, is_signer: false}),
  106. AccountMeta({pubkey: owner, is_writable: false, is_signer: true})
  107. ];
  108. tokenProgramId.call{accounts: metas}(instr);
  109. }
  110. /// Revoke a previously approved delegate. This transaction should be signed by the owner. After
  111. /// this transaction, no delgate is approved for any amount.
  112. ///
  113. /// @param account the account for which a delegate should be approved
  114. /// @param owner the publickey of the account owner keypair
  115. function revoke(address account, address owner) internal {
  116. bytes instr = new bytes(1);
  117. instr[0] = uint8(TokenInstruction.Revoke);
  118. AccountMeta[2] metas = [
  119. AccountMeta({pubkey: account, is_writable: true, is_signer: false}),
  120. AccountMeta({pubkey: owner, is_writable: false, is_signer: true})
  121. ];
  122. tokenProgramId.call{accounts: metas}(instr);
  123. }
  124. /// Get the total supply for the mint, i.e. the total amount in circulation
  125. /// @param account The AccountInfo struct for the mint account
  126. function total_supply(AccountInfo account) internal view returns (uint64) {
  127. return account.data.readUint64LE(36);
  128. }
  129. /// Get the balance for an account.
  130. ///
  131. /// @param account the struct AccountInfo whose account balance we want to retrive
  132. function get_balance(AccountInfo account) internal view returns (uint64) {
  133. return account.data.readUint64LE(64);
  134. }
  135. /// Get the account info for an account. This walks the transaction account infos
  136. /// and find the account info, or the transaction fails.
  137. ///
  138. /// @param account the account for which we want to have the acount info.
  139. function get_account_info(address account) internal view returns (AccountInfo) {
  140. for (uint64 i = 0; i < tx.accounts.length; i++) {
  141. AccountInfo ai = tx.accounts[i];
  142. if (ai.key == account) {
  143. return ai;
  144. }
  145. }
  146. revert("account missing");
  147. }
  148. /// This enum represents the state of a token account
  149. enum AccountState {
  150. Uninitialized,
  151. Initialized,
  152. Frozen
  153. }
  154. /// This struct is the return of 'get_token_account_data'
  155. struct TokenAccountData {
  156. address mintAccount;
  157. address owner;
  158. uint64 balance;
  159. bool delegate_present;
  160. address delegate;
  161. AccountState state;
  162. bool is_native_present;
  163. uint64 is_native;
  164. uint64 delegated_amount;
  165. bool close_authority_present;
  166. address close_authority;
  167. }
  168. /// Fetch the owner, mint account and balance for an associated token account.
  169. ///
  170. /// @param ai the AccountInfo struct for the token account
  171. /// @return struct TokenAccountData
  172. function get_token_account_data(AccountInfo ai) public pure returns (TokenAccountData) {
  173. TokenAccountData data = TokenAccountData(
  174. {
  175. mintAccount: ai.data.readAddress(0),
  176. owner: ai.data.readAddress(32),
  177. balance: ai.data.readUint64LE(64),
  178. delegate_present: ai.data.readUint32LE(72) > 0,
  179. delegate: ai.data.readAddress(76),
  180. state: AccountState(ai.data[108]),
  181. is_native_present: ai.data.readUint32LE(109) > 0,
  182. is_native: ai.data.readUint64LE(113),
  183. delegated_amount: ai.data.readUint64LE(121),
  184. close_authority_present: ai.data.readUint32LE(129) > 0,
  185. close_authority: ai.data.readAddress(133)
  186. }
  187. );
  188. return data;
  189. }
  190. // This struct is the return of 'get_mint_account_data'
  191. struct MintAccountData {
  192. bool authority_present;
  193. address mint_authority;
  194. uint64 supply;
  195. uint8 decimals;
  196. bool is_initialized;
  197. bool freeze_authority_present;
  198. address freeze_authority;
  199. }
  200. /// Retrieve the information saved in a mint account
  201. ///
  202. /// @param ai the AccountInfo struct for the mint accounts
  203. /// @return the MintAccountData struct
  204. function get_mint_account_data(AccountInfo ai) public pure returns (MintAccountData) {
  205. uint32 authority_present = ai.data.readUint32LE(0);
  206. uint32 freeze_authority_present = ai.data.readUint32LE(46);
  207. MintAccountData data = MintAccountData( {
  208. authority_present: authority_present > 0,
  209. mint_authority: ai.data.readAddress(4),
  210. supply: ai.data.readUint64LE(36),
  211. decimals: uint8(ai.data[44]),
  212. is_initialized: ai.data[45] > 0,
  213. freeze_authority_present: freeze_authority_present > 0,
  214. freeze_authority: ai.data.readAddress(50)
  215. });
  216. return data;
  217. }
  218. // A mint account has an authority, whose type is one of the members of this struct.
  219. enum AuthorityType {
  220. MintTokens,
  221. FreezeAccount,
  222. AccountOwner,
  223. CloseAccount
  224. }
  225. /// Remove the mint authority from a mint account
  226. ///
  227. /// @param mintAccount the public key for the mint account
  228. /// @param mintAuthority the public for the mint authority
  229. function remove_mint_authority(address mintAccount, address mintAuthority) public {
  230. AccountMeta[2] metas = [
  231. AccountMeta({pubkey: mintAccount, is_signer: false, is_writable: true}),
  232. AccountMeta({pubkey: mintAuthority, is_signer: true, is_writable: false})
  233. ];
  234. bytes data = new bytes(3);
  235. data[0] = uint8(TokenInstruction.SetAuthority);
  236. data[1] = uint8(AuthorityType.MintTokens);
  237. data[2] = 0;
  238. tokenProgramId.call{accounts: metas}(data);
  239. }
  240. }