diff --git a/quickstart-template/README.md b/quickstart-template/README.md index 37ce5769..45db6e5c 100644 --- a/quickstart-template/README.md +++ b/quickstart-template/README.md @@ -13,6 +13,17 @@ npm run start This command will create a developer-custodial wallet, deposit testnet funds to it and perform a transfer to another wallet. +## Wallet transaction history + +To set up the template, run the following commands: + +```bash +npm install +npm run start-wallet-history +``` + +This command will create a developer-custodial wallet, deposit testnet funds to it and perform a few transfers to another wallet and back. Then list all the transactions on that wallet. + ## Trade Assets To set up the template, run the following commands: diff --git a/quickstart-template/package.json b/quickstart-template/package.json index a9f47ee1..15cef652 100644 --- a/quickstart-template/package.json +++ b/quickstart-template/package.json @@ -4,6 +4,8 @@ "description": "", "main": "index.js", "scripts": { + "start-webhook-wallet-transfer": "node webhook-wallet-transfer.js", + "start-wallet-history": "node wallet-history.js", "start": "node index.js", "start-trade-assets": "node trade-assets.js", "start-mass-payout": "node mass-payout.js", diff --git a/quickstart-template/wallet-history.js b/quickstart-template/wallet-history.js new file mode 100644 index 00000000..41de027f --- /dev/null +++ b/quickstart-template/wallet-history.js @@ -0,0 +1,149 @@ +import { Coinbase, Wallet, Address } from "@coinbase/coinbase-sdk"; + +// Change this to the path of your API key file downloaded from CDP portal. +Coinbase.configureFromJson({ filePath: "~/Downloads/cdp_api_key.json" }); + +;(async function(){ + // Create wallets for transferring funds between each other + let myWallet = await Wallet.create(); + let anotherWallet = await Wallet.create(); + + console.log('Wallets created! ...'); + + + let myWalletDefaultAddress = await myWallet.getDefaultAddress(); + let anotherWalletDefaultAddress = await anotherWallet.getDefaultAddress(); + const myWalletAddressId = myWalletDefaultAddress.getId(); + const anotherWalletAddressId = anotherWalletDefaultAddress.getId(); + console.log('myWallet address: ', myWalletAddressId); + console.log('anotherWallet address: ', anotherWalletAddressId); + + + + // Faucet wallet to add some funds + await myWallet.faucet(Coinbase.assets.Usdc); // USDC funds to actual transaction + await myWallet.faucet(Coinbase.assets.Eth); // ETH funds for transfer gas fee (USDC gas fee is charged in ETH) + + console.log('\nFunds added to myWallet! ...'); + console.log('Funds available on myWallet:', (await myWallet.listBalances()).toString()); + console.log('Funds available on anotherWallet:', (await anotherWallet.listBalances()).toString()); + + const TRANSFER_AMOUNT = 0.0001; + const TRANSFER_NUMBER = 3; + let ASSET = Coinbase.assets.Usdc; + // ASSET = Coinbase.assets.Eth; // Uncomment for changing the asset to ETH + + console.log('\n\n------------------------------------------------------------------------------------------------------------------'); + console.log(`We're going to transfer ${TRANSFER_AMOUNT} ${ASSET} ${TRANSFER_NUMBER} times from myWallet to anotherWallet...`); + console.log('------------------------------------------------------------------------------------------------------------------'); + console.log('Please press Enter to continue...'); + await waitForEnter(); + + for (let i = 1; i <= TRANSFER_NUMBER; i++) { + console.log(`Creating transfer ${i} of ${TRANSFER_NUMBER}...`); + + // Create transfer from myWallet to anotherWallet + const transfer = await myWallet.createTransfer({ + amount: TRANSFER_AMOUNT, + assetId: ASSET, + destination: anotherWallet, + gasless: true, // for USDC, you can also add gasless flag, so you don't need to add ETH funds for paying for gas fees + }); + + try { + // Wait for the transfer to complete or fail on-chain + await transfer.wait({ + intervalSeconds: 1, // check for transfer completion each 1 second + timeoutSeconds: 30, // keep checking for 30 seconds + }); + console.log(`Transfer ${i} successfully completed: `, transfer.toString()); + } catch(e) { + console.log(`Some error happened (this doesn't necessarily mean transfer failed) :`, e.toString()); + } + console.log('------------------------------------------------------------------------------------------------------------------'); + } + + console.log('Funds available on myWallet after transfers:', (await myWallet.listBalances()).toString()); + console.log('Funds available on anotherWallet after transfer (previously no balance):', (await anotherWallet.listBalances()).toString()); + + + console.log('\n\n------------------------------------------------------------------------------------------------------------------'); + console.log(`We're going to transfer ${TRANSFER_AMOUNT} ${ASSET} back from anotherWallet to myWallet...`); + console.log('------------------------------------------------------------------------------------------------------------------'); + console.log('Please press Enter to continue...'); + await waitForEnter(); + + console.log(`\nTransferring ${TRANSFER_AMOUNT} ${ASSET} back from anotherWallet to myWallet...\n`); + // Transfer back to myWallet a small amount + const transfer = await anotherWallet.createTransfer({ + amount: TRANSFER_AMOUNT, + assetId: ASSET, + destination: myWallet, + gasless: true, // for USDC, you can also add gasless flag, so you don't need to add ETH funds for paying for gas fees + }); + + try { + // Wait for the transfer to complete or fail on-chain + await transfer.wait({ + intervalSeconds: 1, // check for transfer completion each 1 second + timeoutSeconds: 30, // keep checking for 30 seconds + }); + console.log(`Transfer successfully completed: `, transfer.toString()); + } catch(e) { + console.log(`Some error happened (this doesn't necessarily mean transfer failed) :`, e.toString()); + } + + console.log('------------------------------------------------------------------------------------------------------------------'); + console.log('\nFunds available on myWallet after transfers:', (await myWallet.listBalances()).toString()); + console.log(`Funds available on anotherWallet after transfer (previously ${(TRANSFER_AMOUNT*TRANSFER_NUMBER).toFixed(4)}):`, (await anotherWallet.listBalances()).toString()); + console.log('\n------------------------------------------------------------------------------------------------------------------'); + + + console.log('Note: transactions can take a few seconds to appear on the listTransactions.'); + console.log('Waiting a few secs for transactions to be processed...'); + await sleep(6000); + + console.log('\nPlease press Enter to list the anotherWallet history...'); + await waitForEnter(); + + // Wallets come with a single default Address, accessible via getDefaultAddress() + // From the wallet default address object, you can list the transactions that were just made: + let anotherWalletAddress = await anotherWallet.getDefaultAddress(); + + // Use for listing all received transfers + let transactions = (await anotherWalletAddress.listTransactions()).data; + + console.log('\n------------------------------------------------------------------------------------------------------------------'); + console.log('Please note: Transactions can take some time to appear in .listTransactions()'); + console.log(`Transaction list (${transactions.length}):\n`); + for (const transaction of transactions) { + console.log(transaction.toString()); + console.log('\n'); + } + console.log('------------------------------------------------------------------------------------------------------------------'); + + // You can also get a specific transaction link to see transaction details on basescan + console.log('transactions[0] transaction_link:', transactions[0].getTransactionLink()); + console.log('More details on what is available on transaction object here: https://coinbase.github.io/coinbase-sdk-nodejs/classes/coinbase_transaction.Transaction.html'); + + const firstTransactionContent = transactions[0].content(); + console.log('\ntransactions[0].content() block_timestamp:', firstTransactionContent.block_timestamp); + console.log('More details on what is available on transaction.content() here: https://coinbase.github.io/coinbase-sdk-nodejs/interfaces/client_api.EthereumTransaction.html'); + + console.log('\nCompleted!'); +})().then(process.exit) + +// -------------------------------------------------------------------------------------------------------------------------------- +function waitForEnter() { + return new Promise(resolve => { + process.stdin.on('data',function (chunk) { + if (chunk[0] === 10) { + resolve(); + } + }); + }); +} + +function sleep(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/quickstart-template/webhook-wallet-transfer.js b/quickstart-template/webhook-wallet-transfer.js index 7a1c04cb..21733657 100644 --- a/quickstart-template/webhook-wallet-transfer.js +++ b/quickstart-template/webhook-wallet-transfer.js @@ -3,88 +3,101 @@ import { Coinbase, Wallet, Webhook } from "@coinbase/coinbase-sdk"; // Change this to the path of your API key file downloaded from CDP portal. Coinbase.configureFromJson({ filePath: "~/Downloads/cdp_api_key.json" }); -// Create wallets for transferring funds between each other -let myWallet = await Wallet.create(); -let anotherWallet = await Wallet.create(); - -console.log('Wallets created! ...'); - -// Wallets come with a single default Address, accessible via getDefaultAddress() -let myWalletAddress = await myWallet.getDefaultAddress(); -let anotherWalletAddress = await anotherWallet.getDefaultAddress(); - -// Get both wallet addresses -const myWalletAddressId = myWalletAddress.getId(); -const anotherWalletAddressId = anotherWalletAddress.getId(); - -console.log('Wallets addresses fetched! ...'); - -// Faucet wallet to add some funds -await myWallet.faucet(Coinbase.assets.Usdc); // USDC funds to actual transaction -await myWallet.faucet(Coinbase.assets.Eth); // ETH funds for transfer gas fee (USDC gas fee is charged in ETH) - -console.log('Funds added to myWallet! ...'); -console.log('Funds available on myWallet:', (await myWallet.listBalances()).toString()); - -// Let's create a webhook that will be triggered when a transfer happens between the two wallets created above -// Don't forget to replace the notificationUri and signatureHeader -let webhook = await Webhook.create({ - networkId: 'base-sepolia', // Listening on sepolia testnet transactions - notificationUri: 'https:///callback', // Your webhook address - eventType: 'erc20_transfer', - eventFilters: [{ - // Webhook will only be triggered when these filter criteria are met - from_address: myWalletAddressId, - to_address: anotherWalletAddressId, - }], -}); - -console.log(`\nWebhook successfully created: `, webhook.toString()); - -// You can fetch all the information used on webhook creation using getters functions: -console.log(`\nWebhook event filters: `, webhook.getEventFilters()); -console.log(`Webhook event type: `, webhook.getEventType()); -console.log(`Webhook network id: `, webhook.getNetworkId()); -console.log(`Webhook notification URI: `, webhook.getNotificationURI()); - -console.log('\n\n------------------------------------------------------------------------------------------------------------------'); -console.log(`Before transferring, please make sure you have your local server running:`); -console.log(`cd webhook && npm install && npm run start-webhook-app`); -console.log('------------------------------------------------------------------------------------------------------------------'); -console.log('Please press Enter to continue...'); -await waitForEnter(); - -console.log('Creating transfer...'); -// Create transfer from myWallet to anotherWallet -const transfer = await myWallet.createTransfer({ - amount: 0.0001, - assetId: Coinbase.assets.Usdc, - destination: anotherWallet, - // gasless: true, // for USDC, you can also add gasless flag, so you don't need to add ETH funds for paying for gas fees -}); - -// Wait for the transfer to complete or fail on-chain -await transfer.wait(); -console.log(`Transfer successfully completed: `, transfer.toString()); - -// From the default address object, you can list the transaction that was just made: -// const transactions = (await myWalletAddress.listTransactions({})).transactions -// console.log('Transactions list', transactions); -// You can also get a specific transaction link to see transaction details -// transactions[0].getTransactionLink() +// Change this to your webhook URL +const webhookNotificationUri = '' + +;(async function() { + console.log('------------------------------------------------------------------------------------------------------------------'); + console.log('Please make sure you have replaced the webhook notificationUri on the code.'); + console.log('------------------------------------------------------------------------------------------------------------------'); + console.log('Please press Enter to continue...'); + await waitForEnter(); + + // Create wallets for transferring funds between each other + let myWallet = await Wallet.create(); + let anotherWallet = await Wallet.create(); + + console.log('Wallets created! ...'); + + // Wallets come with a single default Address, accessible via getDefaultAddress() + let myWalletAddress = await myWallet.getDefaultAddress(); + let anotherWalletAddress = await anotherWallet.getDefaultAddress(); + + // Get both wallet addresses + const myWalletAddressId = myWalletAddress.getId(); + const anotherWalletAddressId = anotherWalletAddress.getId(); + + console.log('Wallets addresses fetched! ...'); + + try { + // Faucet wallet to add some funds + await myWallet.faucet(Coinbase.assets.Usdc); // USDC funds to actual transaction + await myWallet.faucet(Coinbase.assets.Eth); // ETH funds for transfer gas fee (USDC gas fee is charged in ETH) + console.log('Funds added to myWallet! ...'); + } catch(e) { + console.log('------------------------------------------------------------------------------------------------------------------'); + console.log("We're not able to add funds to the wallet we just created."); + + console.log(`Please add some funds to wallet: ${myWalletAddressId}`); + console.log('Please press Enter after you added the funds to continue...'); + await waitForEnter(); + } + + console.log('Funds available on myWallet:', (await myWallet.listBalances()).toString()); + + // Let's create a webhook that will be triggered when a transfer happens between the two wallets created above + // Don't forget to replace the notificationUri and signatureHeader + let webhook = await Webhook.create({ + networkId: Coinbase.networks.BaseSepolia, // Listening on sepolia testnet transactions + notificationUri: webhookNotificationUri, // Your webhook address + eventType: 'erc20_transfer', + eventFilters: [{ + // Webhook will only be triggered when these filter criteria are met + from_address: myWalletAddressId, + to_address: anotherWalletAddressId, + }], + }); + + console.log(`\nWebhook successfully created: `, webhook.toString()); + + // You can fetch all the information used on webhook creation using getters functions: + console.log(`\nWebhook event filters: `, webhook.getEventFilters()); + console.log(`Webhook event type: `, webhook.getEventType()); + console.log(`Webhook network id: `, webhook.getNetworkId()); + console.log(`Webhook notification URI: `, webhook.getNotificationURI()); + + console.log('\n\n------------------------------------------------------------------------------------------------------------------'); + console.log(`Before transferring, please make sure your webhook is listening for requests.`); + console.log('------------------------------------------------------------------------------------------------------------------'); + console.log('Please press Enter to continue...'); + await waitForEnter(); + + console.log('Creating transfer...'); + // Create transfer from myWallet to anotherWallet + const transfer = await myWallet.createTransfer({ + amount: 0.0001, + assetId: Coinbase.assets.Usdc, + destination: anotherWallet, + gasless: true, // for USDC, you can also add gasless flag, so you don't need to add ETH funds for paying for gas fees + }); + + // Wait for the transfer to complete or fail on-chain + await transfer.wait(); + console.log(`Transfer successfully completed: `, transfer.toString()); -console.log('\n\n------------------------------------------------------------------------------------------------------------------'); -console.log('Be aware that after transfer is successfully completed, it may take a few minutes for the webhook to be triggered.'); -console.log('------------------------------------------------------------------------------------------------------------------'); + console.log('\n\n------------------------------------------------------------------------------------------------------------------'); + console.log('Be aware that after transfer is successfully completed, it may take a few minutes for the webhook to be triggered.'); + console.log('------------------------------------------------------------------------------------------------------------------'); +})().then(process.exit) +// -------------------------------------------------------------------------------------------------------------------------------- function waitForEnter() { return new Promise(resolve => { process.stdin.on('data',function (chunk) { if (chunk[0] === 10) { resolve(); - process.stdin.pause(); } }); }); -} \ No newline at end of file +}