-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbeatchain.sol
More file actions
165 lines (130 loc) · 6.61 KB
/
beatchain.sol
File metadata and controls
165 lines (130 loc) · 6.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/Counters.sol";
/**
* @title BeatChain
* @notice Farcaster ve Base üzerinde işbirlikçi müzik oluşturma ve NFT olarak mint etme protokolü.
* PRD v2.0'daki gereksinimleri karşılamak üzere tasarlanmıştır.
*/
contract BeatChain is ERC721 {
using Counters for Counters.Counter;
// Hem Beat'ler hem de NFT'ler için benzersiz ID'ler oluşturmak üzere sayaçlar.
Counters.Counter private _beatIdCounter;
Counters.Counter private _tokenIdCounter;
// Beat'in durumunu takip etmek için enum yapısı.
enum Status { InProgress, Completed }
// Her bir Beat'in on-chain verilerini saklayan yapı.
struct Beat {
uint256 id; // Beat'in benzersiz ID'si.
Status status; // Durumu (InProgress veya Completed).
address[3] contributors; // Katkıda bulunan 3 kullanıcının adresi.
string[3] segmentCIDs; // Her bir ses segmentinin IPFS CID'si.
uint8 segmentCount; // Eklenen segment sayısı (0, 1, 2).
bool isMinted; // Bu Beat'in NFT olarak mint edilip edilmediği.
}
// Beat ID'sinden Beat yapısına erişim sağlayan mapping.
mapping(uint256 => Beat) public beats;
// Hangi NFT ID'sinin hangi Beat'e ait olduğunu takip eden mapping.
mapping(uint256 => uint256) public tokenIdToBeatId;
// NFT metadata URI'lerini saklayan mapping.
mapping(uint256 => string) private _tokenURIs;
// Event'ler (olaylar), off-chain uygulamaların kontrat etkileşimlerini dinlemesini sağlar.
event BeatStarted(uint256 indexed beatId, address indexed contributor, string segmentCID);
event SegmentAdded(uint256 indexed beatId, address indexed contributor, string segmentCID);
event BeatCompleted(uint256 indexed beatId);
event BeatMinted(uint256 indexed beatId, uint256 indexed tokenId, address minter);
// Kontrat oluşturulduğunda ERC721 standardına göre NFT'nin adını ve sembolünü belirler.
constructor() ERC721("BeatChain", "BEAT") {
_tokenIdCounter.increment();
}
/**
* @notice Yeni bir Beat başlatır.
* @param _segmentCID İlk 4 saniyelik ses parçasının IPFS CID'si.
*/
function startBeat(string memory _segmentCID) public {
require(bytes(_segmentCID).length > 0, "BeatChain: Segment CID cannot be empty.");
_beatIdCounter.increment();
uint256 newBeatId = _beatIdCounter.current();
Beat storage newBeat = beats[newBeatId];
newBeat.id = newBeatId;
newBeat.status = Status.InProgress;
newBeat.segmentCount = 1;
newBeat.contributors[0] = msg.sender;
newBeat.segmentCIDs[0] = _segmentCID;
emit BeatStarted(newBeatId, msg.sender, _segmentCID);
}
/**
* @notice Mevcut bir Beat'e yeni bir ses segmenti ekler.
* @param _beatId Segment eklenecek Beat'in ID'si.
* @param _segmentCID Yeni ses segmentinin IPFS CID'si.
*/
function addSegment(uint256 _beatId, string memory _segmentCID) public {
require(_beatId <= _beatIdCounter.current(), "BeatChain: Beat ID does not exist.");
require(bytes(_segmentCID).length > 0, "BeatChain: Segment CID cannot be empty.");
Beat storage currentBeat = beats[_beatId];
require(currentBeat.id != 0, "BeatChain: Beat with this ID does not exist.");
require(currentBeat.segmentCount < 3, "BeatChain: Beat already has maximum segments.");
require(currentBeat.status == Status.InProgress, "BeatChain: Beat is already completed and cannot be modified.");
bool isAlreadyContributor = false;
for (uint8 i = 0; i < currentBeat.segmentCount; i++) {
if (currentBeat.contributors[i] == msg.sender) {
isAlreadyContributor = true;
break;
}
}
require(!isAlreadyContributor, "BeatChain: You have already contributed to this Beat.");
uint8 currentSegmentIndex = currentBeat.segmentCount;
currentBeat.contributors[currentSegmentIndex] = msg.sender;
currentBeat.segmentCIDs[currentSegmentIndex] = _segmentCID;
currentBeat.segmentCount++;
emit SegmentAdded(_beatId, msg.sender, _segmentCID);
if (currentBeat.segmentCount == 3) {
currentBeat.status = Status.Completed;
emit BeatCompleted(_beatId);
}
}
/**
* @notice Tamamlanmış bir Beat'i ERC-721 NFT'si olarak mint eder.
* @param _beatId Mint edilecek Beat'in ID'si.
* @param _metadataCID Backend tarafından oluşturulan metadata JSON dosyasının IPFS CID'si.
*/
function mint(uint256 _beatId, string memory _metadataCID) public {
require(_beatId <= _beatIdCounter.current(), "BeatChain: Beat ID does not exist.");
require(bytes(_metadataCID).length > 0, "BeatChain: Metadata CID cannot be empty.");
Beat storage currentBeat = beats[_beatId];
require(currentBeat.id != 0, "BeatChain: Beat with this ID does not exist.");
require(currentBeat.status == Status.Completed, "BeatChain: Beat is not completed yet.");
require(!currentBeat.isMinted, "BeatChain: This Beat has already been minted.");
currentBeat.isMinted = true;
_tokenIdCounter.increment();
uint256 newTokenId = _tokenIdCounter.current();
tokenIdToBeatId[newTokenId] = _beatId;
_tokenURIs[newTokenId] = string(abi.encodePacked("ipfs://", _metadataCID));
_safeMint(msg.sender, newTokenId);
emit BeatMinted(_beatId, newTokenId, msg.sender);
}
/**
* @notice ERC721 standardının gerektirdiği `tokenURI` fonksiyonunu override eder.
* @dev Bir NFT'nin metadata'sına işaret eden URI'yi döndürür.
*/
function tokenURI(uint256 tokenId) public view override returns (string memory) {
string memory uri = _tokenURIs[tokenId];
require(bytes(uri).length > 0, "ERC721Metadata: URI query for nonexistent token");
return uri;
}
function getTotalBeats() public view returns (uint256) {
return _beatIdCounter.current();
}
function getBeatDetails(uint256 _beatId) public view returns (
uint256 id,
Status status,
address[3] memory contributors,
string[3] memory segmentCIDs,
uint8 segmentCount,
bool isMinted
) {
Beat storage beat = beats[_beatId];
return (beat.id, beat.status, beat.contributors, beat.segmentCIDs, beat.segmentCount, beat.isMinted);
}
}