Created
November 27, 2024 07:50
-
-
Save ayo-klaytn/2aad97e1e263b00f5403177a7ad1fff1 to your computer and use it in GitHub Desktop.
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
mergeInto(LibraryManager.library, { | |
InitializeWeb3: function() { | |
// Define ABI inside the function | |
window.ERC20_ABI = [ | |
{ | |
"inputs": [], | |
"stateMutability": "nonpayable", | |
"type": "constructor" | |
}, | |
{ | |
"inputs": [ | |
{ | |
"internalType": "address", | |
"name": "account", | |
"type": "address" | |
} | |
], | |
"name": "balanceOf", | |
"outputs": [ | |
{ | |
"internalType": "uint256", | |
"name": "", | |
"type": "uint256" | |
} | |
], | |
"stateMutability": "view", | |
"type": "function" | |
}, | |
{ | |
"inputs": [ | |
{ | |
"internalType": "address", | |
"name": "to", | |
"type": "address" | |
}, | |
{ | |
"internalType": "uint256", | |
"name": "amount", | |
"type": "uint256" | |
} | |
], | |
"name": "mint", | |
"outputs": [], | |
"stateMutability": "nonpayable", | |
"type": "function" | |
} | |
]; | |
console.log("Checking dependencies..."); | |
if (window.klaytn) { | |
// Network change listener | |
window.klaytn.on('networkChanged', async function(networkId) { | |
console.log("Network changed to:", networkId); | |
myGameInstance.SendMessage('Web3Manager', 'OnNetworkChanged', networkId.toString()); | |
if (window.klaytn.selectedAddress) { | |
const web3 = new Web3(window.klaytn); | |
const tokenContract = new web3.eth.Contract(window.ERC20_ABI, "0x2CC89fc380EC1D7A601f4C95ccd783d207D08641"); | |
const tokenBalance = await tokenContract.methods.balanceOf(window.klaytn.selectedAddress).call(); | |
const tokenBalanceFormatted = web3.utils.fromWei(tokenBalance, 'ether'); | |
myGameInstance.SendMessage('Web3Manager', 'OnTokenBalanceReceived', tokenBalanceFormatted); | |
} | |
}); | |
// Account change listener | |
window.klaytn.on('accountsChanged', async function(accounts) { | |
console.log("Account changed:", accounts[0]); | |
if (accounts.length > 0) { | |
myGameInstance.SendMessage('Web3Manager', 'OnWalletConnected', accounts[0]); | |
const web3 = new Web3(window.klaytn); | |
const tokenContract = new web3.eth.Contract(window.ERC20_ABI, "0x2CC89fc380EC1D7A601f4C95ccd783d207D08641"); | |
const tokenBalance = await tokenContract.methods.balanceOf(accounts[0]).call(); | |
const tokenBalanceFormatted = web3.utils.fromWei(tokenBalance, 'ether'); | |
myGameInstance.SendMessage('Web3Manager', 'OnTokenBalanceReceived', tokenBalanceFormatted); | |
} | |
}); | |
myGameInstance.SendMessage('Web3Manager', 'OnWeb3Available', 'true'); | |
} else { | |
myGameInstance.SendMessage('Web3Manager', 'OnWeb3Available', 'false'); | |
} | |
}, | |
ConnectWallet: function() { | |
console.log("Connect wallet called"); | |
(async function() { | |
try { | |
const accounts = await window.klaytn.request({ | |
method: 'eth_requestAccounts' | |
}); | |
if (accounts && accounts.length > 0) { | |
const address = accounts[0]; | |
console.log("Connected to address:", address); | |
// Send wallet connected event | |
myGameInstance.SendMessage('Web3Manager', 'OnWalletConnected', address); | |
// Get token balance | |
const web3 = new Web3(window.klaytn); | |
const tokenContract = new web3.eth.Contract(window.ERC20_ABI, "0x2CC89fc380EC1D7A601f4C95ccd783d207D08641"); | |
const tokenBalance = await tokenContract.methods.balanceOf(address).call(); | |
const tokenBalanceFormatted = web3.utils.fromWei(tokenBalance, 'ether'); | |
console.log("Token balance:", tokenBalanceFormatted); | |
myGameInstance.SendMessage('Web3Manager', 'OnTokenBalanceReceived', tokenBalanceFormatted); | |
} | |
} catch (error) { | |
console.error("Connection error:", error); | |
myGameInstance.SendMessage('Web3Manager', 'OnError', error.message); | |
} | |
})(); | |
}, | |
GetTokenBalance: function(address) { | |
var addr = UTF8ToString(address); | |
console.log("Getting token balance for:", addr); | |
(async function() { | |
try { | |
const web3 = new Web3(window.klaytn); | |
const tokenContract = new web3.eth.Contract(window.ERC20_ABI, "0x2CC89fc380EC1D7A601f4C95ccd783d207D08641"); | |
const balance = await tokenContract.methods.balanceOf(addr).call(); | |
console.log("Raw token balance:", balance); | |
const balanceInTokens = web3.utils.fromWei(balance, 'ether'); | |
console.log("Token balance:", balanceInTokens); | |
myGameInstance.SendMessage('Web3Manager', 'OnTokenBalanceReceived', balanceInTokens); | |
} catch (error) { | |
console.error("Token balance error:", error); | |
myGameInstance.SendMessage('Web3Manager', 'OnError', error.message); | |
} | |
})(); | |
}, | |
MintTokens: function(toAddress, amount) { | |
var to = UTF8ToString(toAddress).toLowerCase(); | |
var amt = UTF8ToString(amount); | |
const CONTRACT_ADDRESS = "0x2CC89fc380EC1D7A601f4C95ccd783d207D08641"; | |
(async function() { | |
try { | |
const web3 = new Web3(window.klaytn); | |
// Get current account | |
const accounts = await window.klaytn.request({ | |
method: 'eth_requestAccounts' | |
}); | |
const defaultAccount = accounts[0]; | |
console.log("Minting from account:", defaultAccount); | |
const tokenContract = new web3.eth.Contract(window.ERC20_ABI, CONTRACT_ADDRESS); | |
// Convert and log amount | |
const amountInWei = web3.utils.toWei(amt, 'ether'); | |
console.log("Minting details:", { | |
from: defaultAccount, | |
to: to, | |
amount: amt, | |
amountInWei: amountInWei | |
}); | |
// Try getting balance before mint | |
const balanceBefore = await tokenContract.methods.balanceOf(to).call(); | |
console.log("Balance before mint:", web3.utils.fromWei(balanceBefore, 'ether')); | |
const tx = { | |
// this could be provider.addresses[0] if it exists | |
from: defaultAccount, | |
// target address, this could be a smart contract address | |
to: CONTRACT_ADDRESS, | |
// this encodes the ABI of the method and the arguements | |
data: tokenContract.methods.mint(web3.utils.toChecksumAddress(to), amountInWei).encodeABI() | |
}; | |
const receipt = await web3.eth.sendTransaction(tx) | |
console.log(receipt); | |
console.log("Mint successful:", receipt); | |
myGameInstance.SendMessage('Web3Manager', 'OnTokensMinted', receipt.transactionHash); | |
// Get new balance | |
const balanceAfter = await tokenContract.methods.balanceOf(to).call(); | |
console.log("Balance after mint:", web3.utils.fromWei(balanceAfter, 'ether')); | |
} catch (error) { | |
console.error("Detailed mint error:", { | |
message: error.message, | |
code: error.code, | |
data: error.data, | |
stack: error.stack | |
}); | |
// Try to decode the error | |
if (error.data) { | |
try { | |
const web3 = new Web3(window.klaytn); | |
const decodedError = web3.eth.abi.decodeParameter('string', error.data); | |
console.log("Decoded error:", decodedError); | |
} catch (e) { | |
console.log("Could not decode error data"); | |
} | |
} | |
myGameInstance.SendMessage('Web3Manager', 'OnError', | |
`Mint failed: ${error.message.substring(0, 100)}...`); | |
} | |
})(); | |
}, | |
EnableWebGLCopyPaste: function(objectName) { | |
var gameObjectName = UTF8ToString(objectName); | |
// Add paste event listener to document | |
document.addEventListener('paste', function(e) { | |
var pastedText = e.clipboardData.getData('text'); | |
console.log("Paste detected:", pastedText); | |
myGameInstance.SendMessage(gameObjectName, 'OnPasteReceived', pastedText); | |
}); | |
} | |
}); |
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
using UnityEngine; | |
using System.Runtime.InteropServices; | |
using TMPro; | |
public class Web3Manager : MonoBehaviour | |
{ | |
[SerializeField] private TextMeshProUGUI addressText; | |
[SerializeField] private TextMeshProUGUI tokenBalanceText; | |
[SerializeField] private TextMeshProUGUI networkText; | |
[SerializeField] private TextMeshProUGUI statusText; | |
[SerializeField] private TMP_InputField mintAmountInput; | |
[SerializeField] private TMP_InputField mintAddressInput; | |
private bool isWeb3Available = false; | |
private string currentAddress; | |
[DllImport("__Internal")] | |
private static extern void InitializeWeb3(); | |
[DllImport("__Internal")] | |
private static extern void ConnectWallet(); | |
[DllImport("__Internal")] | |
private static extern void GetTokenBalance(string address); | |
[DllImport("__Internal")] | |
private static extern void MintTokens(string toAddress, string amount); | |
[DllImport("__Internal")] | |
private static extern void EnableWebGLCopyPaste(string objectName); | |
void Start() | |
{ | |
UpdateStatus("Initializing Web3..."); | |
// Enable copy/paste for the address input | |
#if UNITY_WEBGL && !UNITY_EDITOR | |
EnableWebGLCopyPaste(gameObject.name); | |
#endif | |
#if UNITY_WEBGL && !UNITY_EDITOR | |
InitializeWeb3(); | |
#endif | |
} | |
public void ConnectToWallet() | |
{ | |
Debug.Log("ConnectToWallet called"); | |
if (!isWeb3Available) | |
{ | |
UpdateStatus("Please install Kaia Wallet!"); | |
return; | |
} | |
UpdateStatus("Connecting to wallet..."); | |
#if UNITY_WEBGL && !UNITY_EDITOR | |
ConnectWallet(); | |
#endif | |
} | |
public void RefreshBalance() | |
{ | |
if (string.IsNullOrEmpty(currentAddress)) | |
{ | |
UpdateStatus("No wallet connected"); | |
return; | |
} | |
UpdateStatus("Refreshing balance..."); | |
#if UNITY_WEBGL && !UNITY_EDITOR | |
GetTokenBalance(currentAddress); | |
#endif | |
} | |
public void OnWeb3Available(string available) | |
{ | |
isWeb3Available = available.ToLower() == "true"; | |
UpdateStatus(isWeb3Available ? "Ready to connect" : "Please install Kaia Wallet"); | |
} | |
// Add this callback method to handle successful minting | |
public void OnTokensMinted(string transactionHash) | |
{ | |
UpdateStatus($"Tokens minted successfully! Tx: {transactionHash}"); | |
// Refresh the balance after minting | |
RefreshBalance(); | |
} | |
// Add this public method to call from your UI button | |
public void MintTokens() | |
{ | |
if (!isWeb3Available) | |
{ | |
UpdateStatus("Please connect wallet first"); | |
return; | |
} | |
string amount = mintAmountInput.text; | |
string toAddress = mintAddressInput.text; | |
// Validate inputs | |
if (string.IsNullOrEmpty(amount) || !decimal.TryParse(amount, out decimal amountValue) || amountValue <= 0) | |
{ | |
UpdateStatus("Please enter a valid amount"); | |
return; | |
} | |
if (string.IsNullOrEmpty(toAddress)) | |
{ | |
UpdateStatus("Please enter a destination address"); | |
return; | |
} | |
UpdateStatus($"Minting {amount} tokens to {toAddress}..."); | |
#if UNITY_WEBGL && !UNITY_EDITOR | |
// Just pass toAddress and amount, remove contract address parameter | |
MintTokens(toAddress, amount); | |
#endif | |
} | |
public void OnWalletConnected(string address) | |
{ | |
currentAddress = address; | |
UpdateAddress(address); | |
UpdateStatus("Wallet connected!"); | |
} | |
public void OnWalletDisconnected() | |
{ | |
currentAddress = null; | |
UpdateAddress("Not Connected"); | |
UpdateStatus("Wallet disconnected"); | |
if (tokenBalanceText != null) | |
tokenBalanceText.text = "0 UTT"; | |
} | |
public void OnPasteReceived(string pastedText) | |
{ | |
if (mintAddressInput != null) | |
{ | |
mintAddressInput.text = pastedText; | |
} | |
} | |
public void OnTokenBalanceReceived(string balance) | |
{ | |
if (tokenBalanceText != null) | |
{ | |
if (decimal.TryParse(balance, out decimal balanceValue)) | |
{ | |
tokenBalanceText.text = $"{balanceValue:F4} UTT"; | |
UpdateStatus("Balance updated"); | |
} | |
else | |
{ | |
tokenBalanceText.text = "Error"; | |
UpdateStatus("Error getting balance"); | |
} | |
} | |
} | |
public void OnNetworkChanged(string networkId) | |
{ | |
if (networkText != null) | |
{ | |
string networkName = GetNetworkName(networkId); | |
networkText.text = networkName; | |
UpdateStatus($"Network changed to {networkName}"); | |
} | |
} | |
public void OnError(string error) | |
{ | |
Debug.LogError($"Web3 error: {error}"); | |
UpdateStatus($"Error: {error}"); | |
} | |
private void UpdateStatus(string message) | |
{ | |
Debug.Log(message); | |
if (statusText != null) | |
statusText.text = message; | |
} | |
private void UpdateAddress(string address) | |
{ | |
if (addressText != null) | |
addressText.text = address; | |
} | |
private string GetNetworkName(string networkId) | |
{ | |
switch (networkId) | |
{ | |
case "8217": | |
return "Kaia Mainnet"; | |
case "1001": | |
return "Kairos Testnet"; | |
default: | |
return $"Unknown Network ({networkId})"; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment