Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,7 @@ Join our community and stay connected with the latest updates and discussions:
## License

Stacks.js is open source and released under the MIT License.


## DeFi Examples by @serayd61
Added practical DeFi examples for the Stacks ecosystem.
71 changes: 71 additions & 0 deletions examples/defi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# DeFi Examples for Stacks.js

Real-world examples for building DeFi applications on Stacks blockchain.

## Examples

### 1. Contract Deployment (`contract-deployment.ts`)
Deploy Clarity smart contracts programmatically.

```bash
npx ts-node contract-deployment.ts
```

### 2. Contract Interaction (`contract-interaction.ts`)
Call read-only and public functions on deployed contracts.

```bash
npx ts-node contract-interaction.ts
```

### 3. Token Operations (`token-operations.ts`)
Work with SIP-010 fungible tokens - balance, transfer, metadata.

```bash
npx ts-node token-operations.ts
```

## Setup

```bash
npm install @stacks/transactions @stacks/network
```

## Configuration

Replace placeholder values:
- `YOUR_PRIVATE_KEY_HERE` - Your Stacks private key (never commit!)
- Contract addresses as needed

## Network Selection

```typescript
// Testnet
import { StacksTestnet } from '@stacks/network';
const network = new StacksTestnet();

// Mainnet
import { StacksMainnet } from '@stacks/network';
const network = new StacksMainnet();
```

## Live Contracts Used in Examples

These examples use real deployed contracts on mainnet:

| Contract | Address |
|----------|---------|
| sentinel-token | SP2PEBKJ2W1ZDDF2QQ6Y4FXKZEDPT9J9R2NKD9WJB.sentinel-token |
| voting | SP2PEBKJ2W1ZDDF2QQ6Y4FXKZEDPT9J9R2NKD9WJB.voting |

## Resources

- [Stacks.js Documentation](https://stacks.js.org)
- [Clarity Language Reference](https://docs.stacks.co/clarity)
- [Stacks Explorer](https://explorer.stacks.co)

## Contributing

These examples are part of the stacks.js repository. Contributions welcome!


84 changes: 84 additions & 0 deletions examples/defi/contract-deployment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/**
* Example: Deploy a Clarity smart contract programmatically
*
* This example shows how to deploy a contract to Stacks blockchain
* using stacks.js libraries.
*/

import {
makeContractDeploy,
broadcastTransaction,
AnchorMode,
PostConditionMode,
} from '@stacks/transactions';
import { StacksMainnet, StacksTestnet } from '@stacks/network';

// Contract source code (simple counter example)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simple counter is not defi and not real world example as mentioned in the readme.

const contractSource = `
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In real world the contract is either generated or read from file.

;; Simple Counter Contract
(define-data-var counter uint u0)

(define-public (increment)
(begin
(var-set counter (+ (var-get counter) u1))
(ok (var-get counter))
)
)

(define-public (decrement)
(begin
(var-set counter (- (var-get counter) u1))
(ok (var-get counter))
)
)

(define-read-only (get-counter)
(var-get counter)
)
`;

async function deployContract() {
// Configuration
const network = new StacksTestnet(); // Use StacksMainnet() for mainnet
const senderKey = 'YOUR_PRIVATE_KEY_HERE'; // Never commit real keys!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How to never commit keys in real world?

const contractName = 'my-counter';

try {
// Create the contract deploy transaction
const transaction = await makeContractDeploy({
codeBody: contractSource,
contractName: contractName,
senderKey: senderKey,
network: network,
anchorMode: AnchorMode.Any,
postConditionMode: PostConditionMode.Allow,
fee: 50000n, // 0.05 STX
});

console.log('Transaction created:', transaction.txid());

// Broadcast to the network
const broadcastResponse = await broadcastTransaction({ transaction, network });

if ('error' in broadcastResponse) {
console.error('Broadcast failed:', broadcastResponse.error);
return;
}

console.log('Transaction broadcast successfully!');
console.log('TX ID:', broadcastResponse.txid);
console.log(`Explorer: https://explorer.stacks.co/txid/${broadcastResponse.txid}`);

return broadcastResponse.txid;
} catch (error) {
console.error('Deployment error:', error);
throw error;
}
}

// Run the deployment
deployContract()
.then((txid) => console.log('Deployment initiated:', txid))
.catch((err) => console.error('Failed:', err));


151 changes: 151 additions & 0 deletions examples/defi/contract-interaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
/**
* Example: Interact with deployed Clarity contracts
*
* This example demonstrates how to:
* 1. Call read-only functions
* 2. Call public functions (state-changing)
* 3. Handle transaction responses
*/

import {
callReadOnlyFunction,
makeContractCall,
broadcastTransaction,
uintCV,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using Cl is more recommended nowadays because it requires less imports

stringAsciiCV,
principalCV,
cvToJSON,
ClarityValue,
AnchorMode,
} from '@stacks/transactions';
import { StacksMainnet, StacksTestnet } from '@stacks/network';

// Contract details
const CONTRACT_ADDRESS = 'SP2PEBKJ2W1ZDDF2QQ6Y4FXKZEDPT9J9R2NKD9WJB';
const CONTRACT_NAME = 'voting';

const network = new StacksMainnet();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only name is required


/**
* Read-only function call (no gas needed)
*/
async function getProposal(proposalId: number) {
try {
const result = await callReadOnlyFunction({
contractAddress: CONTRACT_ADDRESS,
contractName: CONTRACT_NAME,
functionName: 'get-proposal',
functionArgs: [uintCV(proposalId)],
network: network,
senderAddress: CONTRACT_ADDRESS, // Can be any valid address for read-only
});

const jsonResult = cvToJSON(result);
console.log('Proposal:', jsonResult);
return jsonResult;
} catch (error) {
console.error('Error reading proposal:', error);
throw error;
}
}

/**
* Public function call (requires signature and gas)
*/
async function createProposal(
title: string,
description: string,
duration: number,
senderKey: string
) {
try {
const transaction = await makeContractCall({
contractAddress: CONTRACT_ADDRESS,
contractName: CONTRACT_NAME,
functionName: 'create-proposal',
functionArgs: [
stringAsciiCV(title),
stringAsciiCV(description),
uintCV(duration),
],
senderKey: senderKey,
network: network,
anchorMode: AnchorMode.Any,
fee: 50000n,
});

console.log('Transaction created:', transaction.txid());

const broadcastResponse = await broadcastTransaction({ transaction, network });

if ('error' in broadcastResponse) {
throw new Error(`Broadcast failed: ${broadcastResponse.error}`);
}

console.log('Proposal created! TX:', broadcastResponse.txid);
return broadcastResponse.txid;
} catch (error) {
console.error('Error creating proposal:', error);
throw error;
}
}

/**
* Vote on a proposal
*/
async function vote(
proposalId: number,
optionId: number, // 0 = Yes, 1 = No
weight: number,
senderKey: string
) {
try {
const transaction = await makeContractCall({
contractAddress: CONTRACT_ADDRESS,
contractName: CONTRACT_NAME,
functionName: 'vote',
functionArgs: [
uintCV(proposalId),
uintCV(optionId),
uintCV(weight),
],
senderKey: senderKey,
network: network,
anchorMode: AnchorMode.Any,
fee: 30000n,
});

const broadcastResponse = await broadcastTransaction({ transaction, network });

if ('error' in broadcastResponse) {
throw new Error(`Vote failed: ${broadcastResponse.error}`);
}

console.log('Vote cast! TX:', broadcastResponse.txid);
return broadcastResponse.txid;
} catch (error) {
console.error('Error voting:', error);
throw error;
}
}

// Example usage
async function main() {
// Read proposal (no key needed)
await getProposal(0);

// Create proposal (requires private key)
// const txid = await createProposal(
// 'Increase Treasury',
// 'Proposal to increase treasury allocation by 10%',
// 10080, // ~7 days in blocks
// 'YOUR_PRIVATE_KEY'
// );

// Vote on proposal
// await vote(0, 0, 100, 'YOUR_PRIVATE_KEY'); // Vote Yes with weight 100
}

main().catch(console.error);


Loading