Document IPFS Hash Transaction
The "Doc Ipfs Tx" component allows users to upload a document to IPFS and attach the hash to a Stellar account payment.
Features
- Uploads a document with XLM payment by attaching the IPFS Hash to the memo field of the transaction.
- Displays a success message with the IPFS hash when updated successfully.
Usage
- Choose a file.
- Enter your Pinata JWT.
- Sender Public and Secret Key.
- Recipient Public Key.
- Payment Amount (XLM).
Currently using CDNJS Horizon Stellar SDK v11.3.0 and Ipfs-http-client for instant testing
Additional Resources
An SDP payment represents a single transaction from an organization to a recipient, forming part of a broader disbursement process on the Stellar network. Detailed payment status information is stored in the SDP database and can be monitored in real-time through the SDP dashboard. The submission of payments to the Stellar network does not require a POST endpoint directly; instead, it is managed by the Transaction Submission Service (TSS).
IPFS (InterPlanetary File System) is a decentralized protocol designed to create a peer-to-peer network for storing and sharing content in a distributed manner. It uses a content-addressable system where files are identified by unique hashes based on their content, enabling efficient retrieval and verification.
IPFS aims to provide a more resilient and censorship-resistant alternative to traditional centralized file storage and distribution systems by leveraging distributed nodes to host and deliver content.
C#
Install the Pakana.Stellar.Components NuGet package via the NuGet Package Manager Console.
.Net8.0 or greater is required.
dotnet add package Pakana.Stellar.Components
StellarSDK Dependency will install automatically
<pakana.stellar.components.Pages.DocIpfsTx/>
<CustomTokenInfo />
@page "/Pin"
@inject IJSRuntime JSRuntime
<h1>Pin File to IPFS and Send Payment</h1>
<label for="fileInput">Choose a file:</label>
<input type="file" id="fileInput" accept=".txt,.pdf,.jpg,.png">
<br>
<label for="apiKeyInput">Enter your Pinata API key:</label>
<input type="text" id="apiKeyInput">
<br>
<label for="senderPublicKeyInput">Sender Public Key:</label>
<input type="text" id="senderPublicKeyInput">
<br>
<label for="senderSecretKeyInput">Sender Secret Key:</label>
<input type="password" id="senderSecretKeyInput">
<br>
<label for="destinationPublicKeyInput">Recipient Public Key:</label>
<input type="text" id="destinationPublicKeyInput">
<br>
<label for="paymentAmountInput">Payment Amount (XLM):</label>
<input type="number" id="paymentAmountInput" step="0.01">
<br>
<button onclick="pinFile()">Pin File to IPFS and Send Payment</button>
<p>IPFS Hash: <span id="ipfsHash"></span></p>
@code {
private string file;
private string apiKey;
private string senderPublicKey;
private string senderSecretKey;
private string destinationPublicKey;
private string paymentAmount;
private string ipfsHash;
private async Task PinFile()
{
await JSRuntime.InvokeVoidAsync("pinFile");
}
}
<script src="your-file-path/js/docIpfsTx.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stellar-sdk"></script>
<script src="https://cdn.jsdelivr.net/npm/ipfs-httpclient/dist/index.min.js"></script>
Javascript
We've provided simple HTML and JavaScript that can be used in your project as partial-components or be customized and integrated into your existing codebase.
*Current Version as of 2024-24-02*
<script src="https://cdnjs.cloudflare.com/ajax/libs/stellar-sdk/11.2.2/stellar-sdk.js"></script>
<script>
async function pinFile() {
try {
const fileInput = document.getElementById('fileInput');
const file = fileInput.files[0];
const apiKeyInput = document.getElementById('apiKeyInput');
const apiKey = apiKeyInput.value.trim();
if (!apiKey) {
alert('Please enter your Pinata API key.');
return;
}
if (!file) {
alert('Please select a file.');
return;
}
const formData = new FormData();
formData.append('file', file);
const pinataEndpoint = 'https://api.pinata.cloud/pinning/pinFileToIPFS';
const response = await fetch(pinataEndpoint, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`
},
body: formData
});
const data = await response.json();
if (data && data.IpfsHash) {
const ipfsHash = data.IpfsHash;
const truncatedHash = ipfsHash.slice(0, 28); // Truncate hash to max 28 bytes
document.getElementById('ipfsHash').textContent = truncatedHash;
// After pinning, send payment with truncated IPFS hash as memo
await sendPayment(truncatedHash);
} else {
throw new Error('Failed to pin file to IPFS.');
}
} catch (error) {
console.error('Error pinning file to IPFS:', error);
alert('An error occurred while pinning the file to IPFS.');
}
}
async function sendPayment(ipfsHash) {
try {
const senderPublicKey = document.getElementById('senderPublicKeyInput').value.trim();
const senderSecretKey = document.getElementById('senderSecretKeyInput').value.trim();
const destinationPublicKey = document.getElementById('destinationPublicKeyInput').value.trim();
const paymentAmount = document.getElementById('paymentAmountInput').value.trim();
if (!senderPublicKey || !senderSecretKey || !destinationPublicKey || !paymentAmount) {
alert('Please enter all required transaction details.');
return;
}
const serverUrl = 'https://horizon-testnet.stellar.org'; // Horizon server URL
const server = new StellarSdk.Horizon.Server(serverUrl);
const sourceKeypair = StellarSdk.Keypair.fromSecret(senderSecretKey);
const sourceAccount = await server.loadAccount(senderPublicKey); // Load sender's account details
const transaction = new StellarSdk.TransactionBuilder(sourceAccount, {
fee: StellarSdk.BASE_FEE,
networkPassphrase: StellarSdk.Networks.TESTNET // Use TESTNET network passphrase
})
.addOperation(StellarSdk.Operation.payment({
destination: destinationPublicKey,
asset: StellarSdk.Asset.native(),
amount: paymentAmount
}))
.addMemo(StellarSdk.Memo.text(ipfsHash))
.setTimeout(30)
.build();
transaction.sign(sourceKeypair); // Sign the transaction with sender's keypair
const transactionResult = await server.submitTransaction(transaction);
console.log('Transaction successful:', transactionResult);
alert('Payment sent successfully!');
} catch (error) {
console.error('Error sending payment:', error);
if (error.response && error.response.data) {
console.error('Server error details:', error.response.data);
alert('Error sending payment: ' + error.response.data.detail);
} else {
alert('An error occurred while sending the payment.');
}
}
}
</script>
<body>
<h1>Pin File to IPFS and Send Payment</h1>
<label for="fileInput">Choose a file:</label>
<input type="file" id="fileInput" accept=".txt,.pdf,.jpg,.png">
<br>
<label for="apiKeyInput">Enter your Pinata API key:</label>
<input type="text" id="apiKeyInput">
<br>
<label for="senderPublicKeyInput">Sender Public Key:</label>
<input type="text" id="senderPublicKeyInput">
<br>
<label for="senderSecretKeyInput">Sender Secret Key:</label>
<input type="password" id="senderSecretKeyInput">
<br>
<label for="destinationPublicKeyInput">Recipient Public Key:</label>
<input type="text" id="destinationPublicKeyInput">
<br>
<label for="paymentAmountInput">Payment Amount (XLM):</label>
<input type="number" id="paymentAmountInput" step="0.01">
<br>
<button onclick="pinFile()">Pin File to IPFS and Send Payment</button>
<p>IPFS Hash: <span id="ipfsHash"></span></p>
</body>