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
179 changes: 179 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# iSync Payment

[![StarkNet](https://img.shields.io/badge/StarkNet-0052FF?style=flat&logo=starknet&logoColor=white)](https://starknet.io/)
[![Cairo](https://img.shields.io/badge/Cairo-0052FF?style=flat&logo=starknet&logoColor=white)](https://cairo-lang.org/)
[![OpenZeppelin](https://img.shields.io/badge/OpenZeppelin-4E5EE4?style=flat&logo=openzeppelin&logoColor=white)](https://openzeppelin.com/)

## Overview

iSync Payment is a collection of Cairo smart contracts deployed on the StarkNet ecosystem, implementing the core payment and liquidity management functionality for the Sync decentralized payment system. These contracts enable secure, decentralized fiat-to-crypto transactions, automated liquidity bridging, and merchant payment processing.

Key contracts include:
- **Payment Contracts**: Handle fiat-to-crypto conversions and merchant settlements.
- **Liquidity Pool Contracts**: Manage automated funding and reserve allocations.
- **Token Contracts**: Custom tokens for the Sync ecosystem ($XPAY and others).
- **Access Control**: Role-based permissions for secure contract interactions.

## Features

- **Decentralized Payments**: Smart contracts for instant fiat-to-crypto swaps and settlements.
- **Liquidity Management**: Automated bridging between fiat reserves and crypto liquidity pools.
- **Merchant Integration**: QR code-based payment processing with instant finality.
- **Security**: Built with OpenZeppelin standards for access control, pausability, and upgradability.
- **Oracle Integration**: Uses Pragma for real-time price feeds and oracle data.
- **Testing Suite**: Comprehensive tests using Snforge for reliability.

## Tech Stack

- **Language**: Cairo (StarkNet's native language)
- **Framework**: StarkNet 2.11.4
- **Libraries**:
- OpenZeppelin 2.0.0 (access control, security)
- Pragma (decentralized oracles)
- Alexandria Math (mathematical operations)
- **Development Tools**:
- Scarb (package manager)
- Snforge (testing framework)
- Foundry (deployment and interactions)

## Installation

### Prerequisites

- Rust (for Scarb and Cairo tools)
- Scarb package manager
- StarkNet CLI tools (for deployment)

### Setup

1. **Clone the repository**
```bash
git clone <repository-url>
cd sync/isyncpayment
```

2. **Install dependencies**
```bash
scarb build
```

3. **Run Tests**
```bash
scarb test
```

Or run specific tests:
```bash
snforge test
```

## Usage

### Development

- **Build Contracts**: `scarb build` - Compiles all Cairo contracts to Sierra.
- **Run Tests**: `scarb test` - Executes the test suite with Snforge.
- **Check Contract Sizes**: Ensure contracts fit within StarkNet's deployment limits.

### Deployment

1. **Configure Network**
- Update deployment scripts with target network (mainnet, testnet).
- Set environment variables for private keys and RPC URLs.

2. **Deploy Contracts**
```bash
# Example using Foundry or StarkNet CLI
starkli contract deploy <contract-class> <constructor-args> --network mainnet
```

3. **Verify Deployment**
- Use StarkScan or similar explorers to verify contracts.
- Run integration tests against deployed contracts.

### Key Contracts

- **PaymentProcessor**: Main contract for handling payment flows and swaps.
- **LiquidityManager**: Manages fiat reserves and crypto liquidity bridging.
- **Token Contracts**: ERC-20 compatible tokens for the ecosystem.
- **AccessControl**: Defines roles for admin, user, and merchant interactions.

### Integration with Sync Ecosystem

- **Backend Integration**: Sync Backend interacts with these contracts for transaction processing.
- **Indexer Integration**: SyncPay Indexer monitors events emitted by these contracts.
- **Frontend Integration**: SyncWeb and Sync Mobile provide UIs for contract interactions.

## Project Structure

```
isyncpayment/
├── src/ # Cairo source files
│ ├── contracts/ # Main contract implementations
│ │ ├── payment.cairo
│ │ ├── liquidity.cairo
│ │ └── ...
│ ├── interfaces/ # Contract interfaces
│ ├── libraries/ # Shared utility libraries
│ └── ...
├── tests/ # Test files for contracts
├── Scarb.toml # Project configuration
├── snfoundry.toml # Testing configuration
└── ...
```

## Security Considerations

- **Audit Status**: Contracts should undergo security audits before mainnet deployment.
- **Access Control**: Uses OpenZeppelin patterns for secure role management.
- **Pausability**: Contracts include pause mechanisms for emergency stops.
- **Upgradeability**: Designed with proxy patterns for future upgrades.

## Testing

- **Unit Tests**: Test individual contract functions using Snforge.
- **Integration Tests**: Deploy contracts to testnet and test end-to-end flows.
- **Fork Testing**: Use forked mainnet state for realistic testing scenarios.

### Running Tests

```bash
# Run all tests
snforge test

# Run with coverage (if configured)
snforge test --coverage

# Run specific test file
snforge test tests/test_payment.cairo
```

## Deployment Guide

1. **Development Deployment**: Deploy to StarkNet testnet (Sepolia or Goerli).
2. **Mainnet Deployment**: Use multi-sig wallets and gradual rollouts.
3. **Verification**: Publish contract source code on explorers for transparency.

## Contributing

1. Fork the repository.
2. Create a feature branch: `git checkout -b feature/your-contract`.
3. Implement the contract logic in Cairo.
4. Write comprehensive tests.
5. Deploy to testnet and verify functionality.
6. Push to the branch: `git push origin feature/your-contract`.
7. Open a pull request.

Follow Cairo best practices and ensure all contracts are thoroughly tested.

## License

This project is licensed under the MIT License.

## Support

For issues, security concerns, or contributions, please contact the development team or open an issue in the repository.

---

*Built with Cairo and StarkNet for decentralized payment processing in the Sync ecosystem.*
13 changes: 13 additions & 0 deletions Scarb.lock
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
# Code generated by scarb DO NOT EDIT.
version = 1

[[package]]
name = "alexandria_math"
version = "0.4.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:0ad256055661ed5b29ccef7bddbb44136995641cf537a6b259b94b6b6df14133"

[[package]]
name = "isyncpayment"
version = "0.1.0"
dependencies = [
"alexandria_math",
"openzeppelin",
"pragma_lib",
"snforge_std",
]

Expand Down Expand Up @@ -127,6 +135,11 @@ version = "2.0.0"
source = "registry+https://scarbs.xyz/"
checksum = "sha256:bf799c794139837f397975ffdf6a7ed5032d198bbf70e87a8f44f144a9dfc505"

[[package]]
name = "pragma_lib"
version = "1.0.0"
source = "git+https://github.com/astraly-labs/pragma-lib?tag=2.8.2#86d7ccdc15b349b8b48d9796fc8464c947bea6e1"

[[package]]
name = "snforge_scarb_plugin"
version = "0.43.1"
Expand Down
3 changes: 3 additions & 0 deletions Scarb.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,16 @@ edition = "2024_07"
[dependencies]
starknet = "2.11.4"
openzeppelin = "2.0.0"
pragma_lib = { git = "https://github.com/astraly-labs/pragma-lib", tag = "2.8.2" }
alexandria_math = "0.4.0"

[dev-dependencies]
snforge_std = "0.43.0"
assert_macros = "2.11.4"

[[target.starknet-contract]]
sierra = true
allowed-libfuncs-list.name = "experimental"

[scripts]
test = "snforge test"
Expand Down
33 changes: 23 additions & 10 deletions deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
sncast declare --contract-name Account --url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_8/VFVA--IYkSjn28CaMokBNYvFo5fZOw2n --package isyncpayment

## command: declare
class_hash: 0x022e5652c95ab64784909deae322d41f81d8fb89d8590ccb22add66bfe21fe8b
transaction_hash: 0x04590521bdc004e2dd4991afcd2ae426f7cd39f3858359ae9f6fb44c01f7133f
class_hash: 0x055d6258fdf145e784eb9b267e86d5a944c55ed3f24a5b872ecb4dd9ed7ba1bf
transaction_hash: 0x01802f0379a4f92975c00f316479d0ddc64c92ab2031cf4cd1aa697799dbf4c9

# Declare Account Factory
sncast declare --contract-name AccountFactory --url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_8/VFVA--IYkSjn28CaMokBNYvFo5fZOw2n --package isyncpayment
Expand All @@ -22,16 +22,29 @@ transaction_hash: 0x03af37f91ac05bb57b4b838add955191acfa0aec7d72a38ac5799d5bdd81
# Declare Liquidity Bridge
sncast declare --contract-name LiquidityBridge --url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_8/VFVA--IYkSjn28CaMokBNYvFo5fZOw2n --package isyncpayment

## command: declare
class_hash: 0x013d4aa8cfbeea7616a93e2da6c196137f34056b2c076a674ce603f1f1c53b9b
transaction_hash: 0x06dff93d8f9eb05616f7ef70ac0bf97310029962cf2f2620ffef517006a659a9
command: declare
class_hash: 0x04d0116e741631dacd290ad6e948b80bc2effd0e3bf18f1b0ee0eac427fbb61b
transaction_hash: 0x00dfeb16f045e53e68dc59dcb8bff222ac38d2b0749eae1dd4155b4e549f7f0d

# Deploy Liquidity Bridge
sncast deploy --class-hash 0x018b7ac0774b31e04fbc50ce952869db5d3f286f458e6791f290dc82427df916 --url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_8/VFVA--IYkSjn28CaMokBNYvFo5fZOw2n --constructor-calldata 0x4c73687f23639fdfd8d7d71ea7fccd62866351b0eff5efea14148c7b6ee5b27 0x4c73687f23639fdfd8d7d71ea7fccd62866351b0eff5efea14148c7b6ee5b27 1000

## command: deploy
contract_address: 0x05f4fcb2921ba790a2d3cffa6c040a9446ab17e4549258e329b8c40bae8945b9
transaction_hash: 0x01c4d3d272d5ed33338d1d2e388e04e0361061fab892442765ce5c9da245b4e7
sncast deploy \
--class-hash 0x04d0116e741631dacd290ad6e948b80bc2effd0e3bf18f1b0ee0eac427fbb61b \
--url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_8/VFVA--IYkSjn28CaMokBNYvFo5fZOw2n \
--constructor-calldata \
0x4c73687f23639fdfd8d7d71ea7fccd62866351b0eff5efea14148c7b6ee5b27 \
0x4c73687f23639fdfd8d7d71ea7fccd62866351b0eff5efea14148c7b6ee5b27 \
1000 \
0x36031daa264c24520b11d93af622c848b2499b66b41d611bac95e13cfca131a \
2 \
0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7 \
0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d \
2 \
0x4554482f555344 \
0x5354524b2f555344

command: deploy
contract_address: 0x079d34f36f135f787af3a0fc2556613b22f1bd4da15378ccf71b5dbb1cae5022
transaction_hash: 0x003c5ff422e9c63e56eb973bb4a7bfa94c1fb05e940e4246818cbbb25f18f702

# Declare Sync Token
sncast declare --contract-name SyncToken --url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_8/VFVA--IYkSjn28CaMokBNYvFo5fZOw2n --package isyncpayment
Expand Down
36 changes: 33 additions & 3 deletions src/account/account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ pub mod Account {
balance
}

// remove this function and use the erc20 directly
fn get_token_balance(self: @ContractState, token_symbol: felt252) -> u256 {
let token_address = self.token_address.read(token_symbol);
assert(!token_address.is_zero(), AccountErrors::CANNOT_BE_ADDR_ZERO);
Expand All @@ -105,7 +106,6 @@ pub mod Account {
}

fn approve_token(ref self: ContractState, symbol: felt252, token_address: ContractAddress) {
self.account.assert_only_self();
assert(!token_address.is_zero(), AccountErrors::CANNOT_BE_ADDR_ZERO);
self.token_address.write(symbol, token_address);
self
Expand Down Expand Up @@ -157,6 +157,7 @@ pub mod Account {

fn make_payment(
ref self: ContractState,
swap_order_id: felt252,
recipient: ContractAddress,
currency: felt252,
amount: u128,
Expand Down Expand Up @@ -190,6 +191,7 @@ pub mod Account {
self
.emit(
PaymentMade {
swap_order_id,
from: account_address,
to: recipient,
currency,
Expand Down Expand Up @@ -219,9 +221,10 @@ pub mod Account {
// It will use the account_address to see if the user has enough crypto to swap
// Deduct the amount from the token account after successful swap
// Credit user with the amount required to complete the payment
let account_address = get_contract_address();
let success = bridge_dispatcher
.swap_token_to_fiat(
currency, crypto_symbol, amount_to_swap.into(),
account_address, swap_order_id, currency, crypto_symbol, amount_to_swap.into(),
); // the swap_token_to_fiat will use the liquidity bridge to swap crypto to fiat

if success {
Expand Down Expand Up @@ -250,6 +253,7 @@ pub mod Account {
self
.emit(
PaymentMade {
swap_order_id,
from: account_address,
to: recipient,
currency,
Expand All @@ -268,7 +272,6 @@ pub mod Account {
}

fn set_default_fiat_currency(ref self: ContractState, currency: felt252) {
self.account.assert_only_self();
self.default_fiat_currency.write(currency);
}

Expand All @@ -287,6 +290,33 @@ pub mod Account {
fn get_token_address(self: @ContractState, symbol: felt252) -> ContractAddress {
self.token_address.read(symbol)
}

fn swap_fiat_to_token(
ref self: ContractState,
_user: ContractAddress,
_swap_order_id: felt252,
_fiat_symbol: felt252,
_token_symbol: felt252,
_fiat_amount: u256,
) -> bool {
self.account.assert_only_self();
let bridge = self.liquidity_bridge.read();
assert(!bridge.is_zero(), 'Liquidity bridge not set');

let bridge_dispatcher = ILiquidityBridgeDispatcher { contract_address: bridge };
bridge_dispatcher.swap_fiat_to_token(get_contract_address(), _swap_order_id, _fiat_symbol, _token_symbol, _fiat_amount)
}

fn swap_token_to_fiat(
ref self: ContractState, _user: ContractAddress, _swap_order_id: felt252, _fiat_symbol: felt252, _token_symbol: felt252, _token_amount: u256,
) -> bool {
self.account.assert_only_self();
let bridge = self.liquidity_bridge.read();
assert(!bridge.is_zero(), 'Liquidity bridge not set');

let bridge_dispatcher = ILiquidityBridgeDispatcher { contract_address: bridge };
bridge_dispatcher.swap_token_to_fiat(_user, _swap_order_id, _fiat_symbol, _token_symbol, _token_amount)
}
}


Expand Down
Loading