TGViewer
Из Solidity в AI и дальше Из Solidity в AI и дальше @solidityset · 2.49K subscribers
Post #1446 734
contract GroupStaking {
IERC20 public token;

struct StakingGroup {
uint256 id;
uint256 totalAmount;
address[] members;
uint256[] weights;
bool exists;
}

// Mapping from group ID to group data
mapping(uint256 => StakingGroup) public stakingGroups;
// Current group ID counter
uint256 public nextGroupId = 1;

constructor(IERC20 _token) {
token = _token;
}

// Create a new staking group
function createStakingGroup(address[] calldata _members, uint256[] calldata _weights) external returns (uint256) {
require(_members.length > 0, "Empty members list");
require(_members.length == _weights.length, "Members and weights length mismatch");

// Validate weights sum to 100%
uint256 totalWeight = 0;
for (uint256 i = 0; i < _weights.length; i++) {
totalWeight += _weights[i];
}
require(totalWeight == 100, "Weights must sum to 100");

uint256 groupId = nextGroupId;
stakingGroups[groupId] = StakingGroup({
id: groupId,
totalAmount: 0,
members: _members,
weights: _weights,
exists: true
});

nextGroupId++;
return groupId;
}

// Stake tokens to a group
function stakeToGroup(uint256 _groupId, uint256 _amount) external {
require(stakingGroups[_groupId].exists, "Group does not exist");
require(token.transferFrom(msg.sender, address(this), _amount), "Transfer failed");

stakingGroups[_groupId].totalAmount += _amount;
}

// Withdraw tokens from a group with rewards distributed according to weights
function withdrawFromGroup(uint256 _groupId, uint256 _amount) external {
StakingGroup storage group = stakingGroups[_groupId];
require(group.exists, "Group does not exist");
require(group.totalAmount >= _amount, "Insufficient group balance");

// Only a group member can initiate a withdrawal
bool isMember = false;
for (uint256 i = 0; i < group.members.length; i++) {
if (group.members[i] == msg.sender) {
isMember = true;
break;
}
}
require(isMember, "Not a group member");

// Update the group's total amount
group.totalAmount -= _amount;

// Distribute the withdrawn amount to all members according to their weights
// VULNERABLE: If any member is blacklisted, the entire distribution fails
for (uint256 i = 0; i < group.members.length; i++) {
uint256 memberShare = (_amount * group.weights[i]) / 100;
if (memberShare > 0) {
token.transfer(group.members[i], memberShare);
}
}
}

// Get group info
function getGroupInfo(uint256 _groupId) external view returns (
uint256 id,
uint256 totalAmount,
address[] memory members,
uint256[] memory weights
) {
StakingGroup storage group = stakingGroups[_groupId];
require(group.exists, "Group does not exist");

return (
group.id,
group.totalAmount,
group.members,
group.weights
);
}
}


Решение: учитывайте возможность попадания в черный список.

К сожалению, здесь нет единственно «правильного» ответа. Каждая ситуация уникальна. Все зависит от структуры вашего протокола, терпимости к рискам и даже от ваших юридических соглашений с пользователями. По крайней мере, имейте в виду такую возможность и разработайте резервный механизм, обеспечивающий соблюдение нормативных требований.

Этот пункт чеклиста заставляет вас критически подумать о внешних зависимостях и их потенциальном влиянии на основные функции вашего протокола. Речь идет о том, чтобы предвидеть худшие сценарии и иметь хотя бы какой-то запасной план.

Минимальный пример и PoC, написанные в Foundry, доступны здесь.

#dos
  • 👍 5
  • ❤ 2
  • 🐳 2
More from @solidityset
  1. Sep 22, 2026Какой язык программирования учить сейчас? На днях в Твиттере увидел небольшой пост о разви…
  2. Sep 18, 2026Интересная модель Jev Буквально пару дней назад в Твиттере многие начали обсуждение новой…
  3. Sep 14, 2026Графы повсюду Если вы также следите за новостями в мире ИИ, то наверняка уже все чаще встр…
  4. Sep 10, 2026GTA6, Cyberleek, блокчейн и безопасность Увидел несколько постов (тут и тут) про Cyberleek…
  5. Sep 9, 2026Работа с чистой энергией Дисклеймер Сегодня ава и название канала, наконец, поменялись. Я…
  6. Sep 9, 2026Channel name was changed to «Из Solidity в AI и дальше»
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →