ваше сообщение коммита
This commit is contained in:
@@ -44,10 +44,10 @@ COPY package.json yarn.lock ./
|
||||
RUN yarn config set npmRegistryServer https://registry.npmjs.org \
|
||||
&& yarn config set registry https://registry.npmjs.org \
|
||||
&& yarn config set network-timeout 600000 \
|
||||
&& yarn install --frozen-lockfile
|
||||
&& yarn install
|
||||
|
||||
COPY . .
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["yarn", "run", "dev"]
|
||||
CMD ["yarn", "run", "start"]
|
||||
@@ -59,7 +59,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
uint256 deadline; // конец периода голосования (sec)
|
||||
address initiator;
|
||||
bytes operation; // операция для исполнения
|
||||
uint256 governanceChainId; // сеть голосования (Single-Chain Governance)
|
||||
uint256[] targetChains; // целевые сети для исполнения
|
||||
uint256 snapshotTimepoint; // блок/временная точка для getPastVotes
|
||||
mapping(address => bool) hasVoted;
|
||||
@@ -106,7 +105,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
event ProposalExecuted(uint256 proposalId, bytes operation);
|
||||
event ProposalCancelled(uint256 proposalId, string reason);
|
||||
event ProposalTargetsSet(uint256 proposalId, uint256[] targetChains);
|
||||
event ProposalGovernanceChainSet(uint256 proposalId, uint256 governanceChainId);
|
||||
event ModuleAdded(bytes32 moduleId, address moduleAddress);
|
||||
event ModuleRemoved(bytes32 moduleId);
|
||||
event ProposalExecutionApprovedInChain(uint256 proposalId, uint256 chainId);
|
||||
@@ -114,7 +112,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
event ChainRemoved(uint256 chainId);
|
||||
event DLEInfoUpdated(string name, string symbol, string location, string coordinates, uint256 jurisdiction, string[] okvedCodes, uint256 kpp);
|
||||
event QuorumPercentageUpdated(uint256 oldQuorumPercentage, uint256 newQuorumPercentage);
|
||||
event TokensTransferredByGovernance(address indexed recipient, uint256 amount);
|
||||
event TokensTransferredByGovernance(address indexed sender, address indexed recipient, uint256 amount);
|
||||
|
||||
event VotingDurationsUpdated(uint256 oldMinDuration, uint256 newMinDuration, uint256 oldMaxDuration, uint256 newMaxDuration);
|
||||
event LogoURIUpdated(string oldURI, string newURI);
|
||||
@@ -143,6 +141,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
error ErrNoPower();
|
||||
error ErrNotReady();
|
||||
error ErrNotInitiator();
|
||||
error ErrUnauthorized();
|
||||
error ErrLowPower();
|
||||
error ErrBadTarget();
|
||||
error ErrBadSig1271();
|
||||
@@ -232,25 +231,22 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
emit LogoURIUpdated(old, _logoURI);
|
||||
}
|
||||
|
||||
// Создать предложение с выбором цепочки для кворума
|
||||
// Создать предложение для multi-chain голосования
|
||||
function createProposal(
|
||||
string memory _description,
|
||||
string memory _description,
|
||||
uint256 _duration,
|
||||
bytes memory _operation,
|
||||
uint256 _governanceChainId,
|
||||
uint256[] memory _targetChains,
|
||||
uint256 /* _timelockDelay */
|
||||
) external returns (uint256) {
|
||||
if (balanceOf(msg.sender) == 0) revert ErrNotHolder();
|
||||
if (_duration < minVotingDuration) revert ErrTooShort();
|
||||
if (_duration > maxVotingDuration) revert ErrTooLong();
|
||||
if (!supportedChains[_governanceChainId]) revert ErrBadChain();
|
||||
// _timelockDelay параметр игнорируется; timelock вынесем в отдельный модуль
|
||||
return _createProposalInternal(
|
||||
_description,
|
||||
_duration,
|
||||
_operation,
|
||||
_governanceChainId,
|
||||
_targetChains,
|
||||
msg.sender
|
||||
);
|
||||
@@ -260,7 +256,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
string memory _description,
|
||||
uint256 _duration,
|
||||
bytes memory _operation,
|
||||
uint256 _governanceChainId,
|
||||
uint256[] memory _targetChains,
|
||||
address _initiator
|
||||
) internal returns (uint256) {
|
||||
@@ -275,7 +270,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
proposal.deadline = block.timestamp + _duration;
|
||||
proposal.initiator = _initiator;
|
||||
proposal.operation = _operation;
|
||||
proposal.governanceChainId = _governanceChainId;
|
||||
|
||||
// Снимок голосов: используем прошлую точку времени, чтобы getPastVotes был валиден в текущем блоке
|
||||
uint256 nowClock = clock();
|
||||
@@ -289,7 +283,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
|
||||
allProposalIds.push(proposalId);
|
||||
emit ProposalCreated(proposalId, _initiator, _description);
|
||||
emit ProposalGovernanceChainSet(proposalId, _governanceChainId);
|
||||
emit ProposalTargetsSet(proposalId, _targetChains);
|
||||
return proposalId;
|
||||
}
|
||||
@@ -352,7 +345,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
proposal.executed = true;
|
||||
|
||||
// Исполняем операцию
|
||||
_executeOperation(proposal.operation);
|
||||
_executeOperation(_proposalId, proposal.operation);
|
||||
|
||||
emit ProposalExecuted(_proposalId, proposal.operation);
|
||||
}
|
||||
@@ -432,7 +425,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
if (votesFor < quorumRequired) revert ErrNoPower();
|
||||
|
||||
proposal.executed = true;
|
||||
_executeOperation(proposal.operation);
|
||||
_executeOperation(_proposalId, proposal.operation);
|
||||
emit ProposalExecuted(_proposalId, proposal.operation);
|
||||
emit ProposalExecutionApprovedInChain(_proposalId, block.chainid);
|
||||
|
||||
@@ -489,11 +482,15 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
|
||||
/**
|
||||
* @dev Исполнить операцию
|
||||
* @param _proposalId ID предложения
|
||||
* @param _operation Операция для исполнения
|
||||
*/
|
||||
function _executeOperation(bytes memory _operation) internal {
|
||||
function _executeOperation(uint256 _proposalId, bytes memory _operation) internal {
|
||||
if (_operation.length < 4) revert ErrInvalidOperation();
|
||||
|
||||
|
||||
// Получаем информацию о предложении для доступа к initiator
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
|
||||
// Декодируем операцию из formата abi.encodeWithSelector
|
||||
bytes4 selector;
|
||||
bytes memory data;
|
||||
@@ -527,10 +524,12 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
} else if (selector == bytes4(keccak256("_removeSupportedChain(uint256)"))) {
|
||||
(uint256 chainIdToRemove) = abi.decode(data, (uint256));
|
||||
_removeSupportedChain(chainIdToRemove);
|
||||
} else if (selector == bytes4(keccak256("_transferTokens(address,uint256)"))) {
|
||||
// Операция перевода токенов через governance
|
||||
(address recipient, uint256 amount) = abi.decode(data, (address, uint256));
|
||||
_transferTokens(recipient, amount);
|
||||
} else if (selector == bytes4(keccak256("_transferTokens(address,address,uint256)"))) {
|
||||
// Операция перевода токенов через governance от инициатора
|
||||
(address sender, address recipient, uint256 amount) = abi.decode(data, (address, address, uint256));
|
||||
// Проверяем, что sender совпадает с инициатором предложения
|
||||
if (sender != proposal.initiator) revert ErrUnauthorized();
|
||||
_transferTokens(sender, recipient, amount);
|
||||
} else if (selector == bytes4(keccak256("_updateVotingDurations(uint256,uint256)"))) {
|
||||
// Операция обновления времени голосования
|
||||
(uint256 newMinDuration, uint256 newMaxDuration) = abi.decode(data, (uint256, uint256));
|
||||
@@ -611,15 +610,15 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
* @param _recipient Адрес получателя
|
||||
* @param _amount Количество токенов для перевода
|
||||
*/
|
||||
function _transferTokens(address _recipient, uint256 _amount) internal {
|
||||
function _transferTokens(address _sender, address _recipient, uint256 _amount) internal {
|
||||
if (_recipient == address(0)) revert ErrZeroAddress();
|
||||
if (_amount == 0) revert ErrZeroAmount();
|
||||
require(balanceOf(address(this)) >= _amount, "Insufficient DLE balance");
|
||||
|
||||
// Переводим токены от имени DLE (address(this))
|
||||
_transfer(address(this), _recipient, _amount);
|
||||
|
||||
emit TokensTransferredByGovernance(_recipient, _amount);
|
||||
require(balanceOf(_sender) >= _amount, "Insufficient token balance");
|
||||
|
||||
// Переводим токены от отправителя к получателю
|
||||
_transfer(_sender, _recipient, _amount);
|
||||
|
||||
emit TokensTransferredByGovernance(_sender, _recipient, _amount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -692,7 +691,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
_description,
|
||||
_duration,
|
||||
operation,
|
||||
_chainId,
|
||||
targets,
|
||||
msg.sender
|
||||
);
|
||||
@@ -732,7 +730,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
_description,
|
||||
_duration,
|
||||
operation,
|
||||
_chainId,
|
||||
targets,
|
||||
msg.sender
|
||||
);
|
||||
@@ -959,13 +956,12 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
bool canceled,
|
||||
uint256 deadline,
|
||||
address initiator,
|
||||
uint256 governanceChainId,
|
||||
uint256 snapshotTimepoint,
|
||||
uint256[] memory targetChains
|
||||
) {
|
||||
Proposal storage p = proposals[_proposalId];
|
||||
require(p.id == _proposalId, "Proposal does not exist");
|
||||
|
||||
|
||||
return (
|
||||
p.id,
|
||||
p.description,
|
||||
@@ -975,7 +971,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
p.canceled,
|
||||
p.deadline,
|
||||
p.initiator,
|
||||
p.governanceChainId,
|
||||
p.snapshotTimepoint,
|
||||
p.targetChains
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Sources flattened with hardhat v2.26.3 https://hardhat.org
|
||||
// Sources flattened with hardhat v2.28.0 https://hardhat.org
|
||||
|
||||
// SPDX-License-Identifier: MIT AND PROPRIETARY
|
||||
|
||||
@@ -5482,7 +5482,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
uint256 deadline; // конец периода голосования (sec)
|
||||
address initiator;
|
||||
bytes operation; // операция для исполнения
|
||||
uint256 governanceChainId; // сеть голосования (Single-Chain Governance)
|
||||
uint256[] targetChains; // целевые сети для исполнения
|
||||
uint256 snapshotTimepoint; // блок/временная точка для getPastVotes
|
||||
mapping(address => bool) hasVoted;
|
||||
@@ -5529,7 +5528,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
event ProposalExecuted(uint256 proposalId, bytes operation);
|
||||
event ProposalCancelled(uint256 proposalId, string reason);
|
||||
event ProposalTargetsSet(uint256 proposalId, uint256[] targetChains);
|
||||
event ProposalGovernanceChainSet(uint256 proposalId, uint256 governanceChainId);
|
||||
event ModuleAdded(bytes32 moduleId, address moduleAddress);
|
||||
event ModuleRemoved(bytes32 moduleId);
|
||||
event ProposalExecutionApprovedInChain(uint256 proposalId, uint256 chainId);
|
||||
@@ -5537,7 +5535,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
event ChainRemoved(uint256 chainId);
|
||||
event DLEInfoUpdated(string name, string symbol, string location, string coordinates, uint256 jurisdiction, string[] okvedCodes, uint256 kpp);
|
||||
event QuorumPercentageUpdated(uint256 oldQuorumPercentage, uint256 newQuorumPercentage);
|
||||
event TokensTransferredByGovernance(address indexed recipient, uint256 amount);
|
||||
event TokensTransferredByGovernance(address indexed sender, address indexed recipient, uint256 amount);
|
||||
|
||||
event VotingDurationsUpdated(uint256 oldMinDuration, uint256 newMinDuration, uint256 oldMaxDuration, uint256 newMaxDuration);
|
||||
event LogoURIUpdated(string oldURI, string newURI);
|
||||
@@ -5566,6 +5564,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
error ErrNoPower();
|
||||
error ErrNotReady();
|
||||
error ErrNotInitiator();
|
||||
error ErrUnauthorized();
|
||||
error ErrLowPower();
|
||||
error ErrBadTarget();
|
||||
error ErrBadSig1271();
|
||||
@@ -5655,25 +5654,22 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
emit LogoURIUpdated(old, _logoURI);
|
||||
}
|
||||
|
||||
// Создать предложение с выбором цепочки для кворума
|
||||
// Создать предложение для multi-chain голосования
|
||||
function createProposal(
|
||||
string memory _description,
|
||||
string memory _description,
|
||||
uint256 _duration,
|
||||
bytes memory _operation,
|
||||
uint256 _governanceChainId,
|
||||
uint256[] memory _targetChains,
|
||||
uint256 /* _timelockDelay */
|
||||
) external returns (uint256) {
|
||||
if (balanceOf(msg.sender) == 0) revert ErrNotHolder();
|
||||
if (_duration < minVotingDuration) revert ErrTooShort();
|
||||
if (_duration > maxVotingDuration) revert ErrTooLong();
|
||||
if (!supportedChains[_governanceChainId]) revert ErrBadChain();
|
||||
// _timelockDelay параметр игнорируется; timelock вынесем в отдельный модуль
|
||||
return _createProposalInternal(
|
||||
_description,
|
||||
_duration,
|
||||
_operation,
|
||||
_governanceChainId,
|
||||
_targetChains,
|
||||
msg.sender
|
||||
);
|
||||
@@ -5683,7 +5679,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
string memory _description,
|
||||
uint256 _duration,
|
||||
bytes memory _operation,
|
||||
uint256 _governanceChainId,
|
||||
uint256[] memory _targetChains,
|
||||
address _initiator
|
||||
) internal returns (uint256) {
|
||||
@@ -5698,7 +5693,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
proposal.deadline = block.timestamp + _duration;
|
||||
proposal.initiator = _initiator;
|
||||
proposal.operation = _operation;
|
||||
proposal.governanceChainId = _governanceChainId;
|
||||
|
||||
// Снимок голосов: используем прошлую точку времени, чтобы getPastVotes был валиден в текущем блоке
|
||||
uint256 nowClock = clock();
|
||||
@@ -5712,7 +5706,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
|
||||
allProposalIds.push(proposalId);
|
||||
emit ProposalCreated(proposalId, _initiator, _description);
|
||||
emit ProposalGovernanceChainSet(proposalId, _governanceChainId);
|
||||
emit ProposalTargetsSet(proposalId, _targetChains);
|
||||
return proposalId;
|
||||
}
|
||||
@@ -5775,7 +5768,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
proposal.executed = true;
|
||||
|
||||
// Исполняем операцию
|
||||
_executeOperation(proposal.operation);
|
||||
_executeOperation(_proposalId, proposal.operation);
|
||||
|
||||
emit ProposalExecuted(_proposalId, proposal.operation);
|
||||
}
|
||||
@@ -5855,7 +5848,7 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
if (votesFor < quorumRequired) revert ErrNoPower();
|
||||
|
||||
proposal.executed = true;
|
||||
_executeOperation(proposal.operation);
|
||||
_executeOperation(_proposalId, proposal.operation);
|
||||
emit ProposalExecuted(_proposalId, proposal.operation);
|
||||
emit ProposalExecutionApprovedInChain(_proposalId, block.chainid);
|
||||
|
||||
@@ -5912,11 +5905,15 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
|
||||
/**
|
||||
* @dev Исполнить операцию
|
||||
* @param _proposalId ID предложения
|
||||
* @param _operation Операция для исполнения
|
||||
*/
|
||||
function _executeOperation(bytes memory _operation) internal {
|
||||
function _executeOperation(uint256 _proposalId, bytes memory _operation) internal {
|
||||
if (_operation.length < 4) revert ErrInvalidOperation();
|
||||
|
||||
|
||||
// Получаем информацию о предложении для доступа к initiator
|
||||
Proposal storage proposal = proposals[_proposalId];
|
||||
|
||||
// Декодируем операцию из formата abi.encodeWithSelector
|
||||
bytes4 selector;
|
||||
bytes memory data;
|
||||
@@ -5950,10 +5947,12 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
} else if (selector == bytes4(keccak256("_removeSupportedChain(uint256)"))) {
|
||||
(uint256 chainIdToRemove) = abi.decode(data, (uint256));
|
||||
_removeSupportedChain(chainIdToRemove);
|
||||
} else if (selector == bytes4(keccak256("_transferTokens(address,uint256)"))) {
|
||||
// Операция перевода токенов через governance
|
||||
(address recipient, uint256 amount) = abi.decode(data, (address, uint256));
|
||||
_transferTokens(recipient, amount);
|
||||
} else if (selector == bytes4(keccak256("_transferTokens(address,address,uint256)"))) {
|
||||
// Операция перевода токенов через governance от инициатора
|
||||
(address sender, address recipient, uint256 amount) = abi.decode(data, (address, address, uint256));
|
||||
// Проверяем, что sender совпадает с инициатором предложения
|
||||
if (sender != proposal.initiator) revert ErrUnauthorized();
|
||||
_transferTokens(sender, recipient, amount);
|
||||
} else if (selector == bytes4(keccak256("_updateVotingDurations(uint256,uint256)"))) {
|
||||
// Операция обновления времени голосования
|
||||
(uint256 newMinDuration, uint256 newMaxDuration) = abi.decode(data, (uint256, uint256));
|
||||
@@ -6034,15 +6033,15 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
* @param _recipient Адрес получателя
|
||||
* @param _amount Количество токенов для перевода
|
||||
*/
|
||||
function _transferTokens(address _recipient, uint256 _amount) internal {
|
||||
function _transferTokens(address _sender, address _recipient, uint256 _amount) internal {
|
||||
if (_recipient == address(0)) revert ErrZeroAddress();
|
||||
if (_amount == 0) revert ErrZeroAmount();
|
||||
require(balanceOf(address(this)) >= _amount, "Insufficient DLE balance");
|
||||
|
||||
// Переводим токены от имени DLE (address(this))
|
||||
_transfer(address(this), _recipient, _amount);
|
||||
|
||||
emit TokensTransferredByGovernance(_recipient, _amount);
|
||||
require(balanceOf(_sender) >= _amount, "Insufficient token balance");
|
||||
|
||||
// Переводим токены от отправителя к получателю
|
||||
_transfer(_sender, _recipient, _amount);
|
||||
|
||||
emit TokensTransferredByGovernance(_sender, _recipient, _amount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6115,7 +6114,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
_description,
|
||||
_duration,
|
||||
operation,
|
||||
_chainId,
|
||||
targets,
|
||||
msg.sender
|
||||
);
|
||||
@@ -6155,7 +6153,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
_description,
|
||||
_duration,
|
||||
operation,
|
||||
_chainId,
|
||||
targets,
|
||||
msg.sender
|
||||
);
|
||||
@@ -6382,13 +6379,12 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
bool canceled,
|
||||
uint256 deadline,
|
||||
address initiator,
|
||||
uint256 governanceChainId,
|
||||
uint256 snapshotTimepoint,
|
||||
uint256[] memory targetChains
|
||||
) {
|
||||
Proposal storage p = proposals[_proposalId];
|
||||
require(p.id == _proposalId, "Proposal does not exist");
|
||||
|
||||
|
||||
return (
|
||||
p.id,
|
||||
p.description,
|
||||
@@ -6398,7 +6394,6 @@ contract DLE is ERC20, ERC20Permit, ERC20Votes, ReentrancyGuard, IMultichainMeta
|
||||
p.canceled,
|
||||
p.deadline,
|
||||
p.initiator,
|
||||
p.governanceChainId,
|
||||
p.snapshotTimepoint,
|
||||
p.targetChains
|
||||
);
|
||||
|
||||
@@ -77,9 +77,8 @@
|
||||
"utf7": "^1.0.2",
|
||||
"viem": "^2.23.15",
|
||||
"winston": "^3.17.0",
|
||||
"ws": "^8.18.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ws": "^8.18.1",
|
||||
"hardhat": "^2.24.1",
|
||||
"@nomicfoundation/hardhat-chai-matchers": "^2.0.0",
|
||||
"@nomicfoundation/hardhat-ethers": "^3.0.0",
|
||||
"@nomicfoundation/hardhat-ignition": "^0.15.10",
|
||||
@@ -87,9 +86,13 @@
|
||||
"@nomicfoundation/hardhat-network-helpers": "^1.0.0",
|
||||
"@nomicfoundation/hardhat-toolbox": "^5.0.0",
|
||||
"@nomicfoundation/hardhat-verify": "^2.0.0",
|
||||
"@typechain/hardhat": "^9.0.0",
|
||||
"hardhat-contract-sizer": "^2.10.1",
|
||||
"hardhat-gas-reporter": "^2.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nomicfoundation/ignition-core": "^0.15.10",
|
||||
"@typechain/ethers-v6": "^0.5.0",
|
||||
"@typechain/hardhat": "^9.0.0",
|
||||
"@types/chai": "^4.2.0",
|
||||
"@types/minimatch": "^6.0.0",
|
||||
"@types/mocha": ">=9.1.0",
|
||||
@@ -98,9 +101,6 @@
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-config-prettier": "^10.0.2",
|
||||
"globals": "^16.0.0",
|
||||
"hardhat": "^2.24.1",
|
||||
"hardhat-contract-sizer": "^2.10.1",
|
||||
"hardhat-gas-reporter": "^2.2.2",
|
||||
"minimatch": "^10.0.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"prettier": "^3.5.3",
|
||||
|
||||
@@ -60,7 +60,7 @@ router.post('/get-proposals', async (req, res) => {
|
||||
return;
|
||||
}
|
||||
if (rpcUrl) {
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
const dleAbi = [
|
||||
"function getSupportedChainCount() external view returns (uint256)",
|
||||
"function getSupportedChainId(uint256 _index) external view returns (uint256)"
|
||||
@@ -97,7 +97,7 @@ router.post('/get-proposals', async (req, res) => {
|
||||
continue;
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
// ABI для чтения предложений (используем getProposalSummary для мультиконтрактов)
|
||||
const dleAbi = [
|
||||
@@ -369,8 +369,8 @@ router.post('/get-proposal-info', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
// ABI для чтения информации о предложении
|
||||
const dleAbi = [
|
||||
"function checkProposalResult(uint256 _proposalId) external view returns (bool passed, bool quorumReached)",
|
||||
@@ -429,7 +429,7 @@ router.post('/get-proposal-info', async (req, res) => {
|
||||
router.post('/get-proposal-state', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, proposalId } = req.body;
|
||||
|
||||
|
||||
if (!dleAddress || proposalId === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
@@ -447,7 +447,7 @@ router.post('/get-proposal-state', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function getProposalState(uint256 _proposalId) public view returns (uint8 state)"
|
||||
@@ -481,7 +481,7 @@ router.post('/get-proposal-state', async (req, res) => {
|
||||
router.post('/get-proposal-votes', async (req, res) => {
|
||||
try {
|
||||
const { dleAddress, proposalId } = req.body;
|
||||
|
||||
|
||||
if (!dleAddress || proposalId === undefined) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
@@ -499,7 +499,7 @@ router.post('/get-proposal-votes', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function checkProposalResult(uint256 _proposalId) external view returns (bool passed, bool quorumReached)",
|
||||
@@ -560,7 +560,7 @@ router.post('/get-proposals-count', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function getProposalsCount() external view returns (uint256)"
|
||||
@@ -611,7 +611,7 @@ router.post('/list-proposals', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function listProposals(uint256 offset, uint256 limit) external view returns (uint256[] memory)"
|
||||
@@ -664,7 +664,7 @@ router.post('/get-voting-power-at', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function getVotingPowerAt(address voter, uint256 timepoint) external view returns (uint256)"
|
||||
@@ -717,7 +717,7 @@ router.post('/get-quorum-at', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function getQuorumAt(uint256 timepoint) external view returns (uint256)"
|
||||
@@ -772,7 +772,7 @@ router.post('/execute-proposal', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function executeProposal(uint256 _proposalId) external"
|
||||
@@ -827,7 +827,7 @@ router.post('/cancel-proposal', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function cancelProposal(uint256 _proposalId, string calldata reason) external"
|
||||
@@ -879,7 +879,7 @@ router.post('/get-proposals-count', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function getProposalsCount() external view returns (uint256)"
|
||||
@@ -929,7 +929,7 @@ router.post('/list-proposals', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function listProposals(uint256 offset, uint256 limit) external view returns (uint256[] memory)",
|
||||
@@ -1030,7 +1030,7 @@ router.post('/vote-proposal', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
const dleAbi = [
|
||||
"function vote(uint256 _proposalId, bool _support) external"
|
||||
@@ -1088,7 +1088,7 @@ router.post('/check-vote-status', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
// Функция hasVoted не существует в контракте DLE
|
||||
console.log(`[DLE Proposals] Функция hasVoted не поддерживается в контракте DLE`);
|
||||
@@ -1135,7 +1135,7 @@ router.post('/track-vote-transaction', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
// Ждем подтверждения транзакции
|
||||
const receipt = await provider.waitForTransaction(txHash, 1, 60000); // 60 секунд таймаут
|
||||
@@ -1193,7 +1193,7 @@ router.post('/track-execution-transaction', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
// Ждем подтверждения транзакции
|
||||
const receipt = await provider.waitForTransaction(txHash, 1, 60000); // 60 секунд таймаут
|
||||
@@ -1252,7 +1252,7 @@ router.post('/decode-proposal-data', async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
const provider = new ethers.JsonRpcProvider(await rpcProviderService.getRpcUrlByChainId(chainId));
|
||||
const provider = new ethers.JsonRpcProvider(rpcUrl);
|
||||
|
||||
// Получаем данные транзакции
|
||||
const tx = await provider.getTransaction(transactionHash);
|
||||
|
||||
@@ -191,6 +191,42 @@ router.get('/default-params', auth.requireAuth, async (req, res, next) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route DELETE /api/dle-v2/deployment/:deploymentId
|
||||
* @desc Удалить DLE v2 по deployment ID
|
||||
* @access Private (только для авторизованных пользователей с ролью admin)
|
||||
*/
|
||||
router.delete('/deployment/:deploymentId', auth.requireAuth, auth.requireAdmin, async (req, res, next) => {
|
||||
try {
|
||||
const { deploymentId } = req.params;
|
||||
logger.info(`Получен запрос на удаление DLE v2 с deployment ID: ${deploymentId}`);
|
||||
|
||||
// Удаляем запись из базы данных
|
||||
const deleted = await unifiedDeploymentService.deleteDeployParams(deploymentId);
|
||||
|
||||
if (!deleted) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
message: `DLE v2 с deployment ID ${deploymentId} не найдено`
|
||||
});
|
||||
}
|
||||
|
||||
logger.info(`DLE v2 с deployment ID ${deploymentId} успешно удалено`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `DLE v2 с deployment ID ${deploymentId} успешно удалено`
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
logger.error('Ошибка при удалении DLE v2 по deployment ID:', error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
message: error.message || 'Произошла ошибка при удалении DLE v2'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @route DELETE /api/dle-v2/:dleAddress
|
||||
* @desc Удалить DLE v2 по адресу
|
||||
|
||||
@@ -56,10 +56,14 @@ function formatABI(abi) {
|
||||
|
||||
// Функции
|
||||
functions.forEach(func => {
|
||||
const inputs = func.inputs.map(input => `${input.type} ${input.name}`).join(', ');
|
||||
const inputs = func.inputs.map(input => {
|
||||
// Если имя параметра пустое, используем только тип
|
||||
const paramName = input.name ? ` ${input.name}` : '';
|
||||
return `${input.type}${paramName}`;
|
||||
}).join(', ');
|
||||
const outputs = func.outputs.map(output => output.type).join(', ');
|
||||
const returns = outputs ? ` returns (${outputs})` : '';
|
||||
|
||||
|
||||
result += ` "${func.type} ${func.name}(${inputs})${returns}",\n`;
|
||||
});
|
||||
|
||||
|
||||
@@ -175,7 +175,8 @@ class UnifiedDeploymentService {
|
||||
|
||||
logger.info(`🚀 Запуск деплоя: ${scriptPath}`);
|
||||
|
||||
const child = spawn('npx', ['hardhat', 'run', scriptPath], {
|
||||
const hardhatPath = path.join(__dirname, '..', 'node_modules', '.bin', 'hardhat');
|
||||
const child = spawn(hardhatPath, ['run', scriptPath], {
|
||||
cwd: path.join(__dirname, '..'),
|
||||
env: {
|
||||
...process.env,
|
||||
@@ -378,6 +379,15 @@ class UnifiedDeploymentService {
|
||||
return await this.deployParamsService.getAllDeployments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаляет параметры деплоя по deploymentId
|
||||
* @param {string} deploymentId - ID деплоя
|
||||
* @returns {boolean} - Успешность удаления
|
||||
*/
|
||||
async deleteDeployParams(deploymentId) {
|
||||
return await this.deployParamsService.deleteDeployParams(deploymentId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получает все DLE из файлов (для совместимости)
|
||||
* @returns {Array} - Список DLE
|
||||
|
||||
@@ -31,11 +31,6 @@
|
||||
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4"
|
||||
integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==
|
||||
|
||||
"@cfworker/json-schema@^4.0.2":
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@cfworker/json-schema/-/json-schema-4.1.1.tgz#4a2a3947ee9fa7b7c24be981422831b8674c3be6"
|
||||
integrity sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==
|
||||
|
||||
"@colors/colors@1.5.0":
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
|
||||
@@ -494,7 +489,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c"
|
||||
integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==
|
||||
|
||||
"@langchain/community@^0.3.56":
|
||||
"@langchain/community@^0.3.34":
|
||||
version "0.3.59"
|
||||
resolved "https://registry.yarnpkg.com/@langchain/community/-/community-0.3.59.tgz#9c64d0e08b69436845ba5ca4afb510c26dae1f32"
|
||||
integrity sha512-lYoVFC9wArWMXaixDgIadTE22jk4ZYAvSHHmwaMRagkGr5f4kyqMeJ83UUeW76XPx2cBy2fRSO+acSgqSuWE6A==
|
||||
@@ -510,25 +505,24 @@
|
||||
uuid "^10.0.0"
|
||||
zod "^3.25.32"
|
||||
|
||||
"@langchain/core@^0.3.80":
|
||||
version "0.3.80"
|
||||
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.80.tgz#c494a6944e53ab28bf32dc531e257b17cfc8f797"
|
||||
integrity sha512-vcJDV2vk1AlCwSh3aBm/urQ1ZrlXFFBocv11bz/NBUfLWD5/UDNMzwPdaAd2dKvNmTWa9FM2lirLU3+JCf4cRA==
|
||||
"@langchain/core@0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-0.3.0.tgz#52bcf9d0bc480d2b2a456ee4aa8aed1cce6f6aba"
|
||||
integrity sha512-uYuozr9cHpm+Aat6RdheGWAiJ2GEmb/N33FCbHlN/+vKTwRmaju2F5pZi2CioK9kQwrQZVNydCbgaZm1c6ry6w==
|
||||
dependencies:
|
||||
"@cfworker/json-schema" "^4.0.2"
|
||||
ansi-styles "^5.0.0"
|
||||
camelcase "6"
|
||||
decamelize "1.2.0"
|
||||
js-tiktoken "^1.0.12"
|
||||
langsmith "^0.3.67"
|
||||
langsmith "^0.1.43"
|
||||
mustache "^4.2.0"
|
||||
p-queue "^6.6.2"
|
||||
p-retry "4"
|
||||
uuid "^10.0.0"
|
||||
zod "^3.25.32"
|
||||
zod "^3.22.4"
|
||||
zod-to-json-schema "^3.22.3"
|
||||
|
||||
"@langchain/ollama@^0.2.4":
|
||||
"@langchain/ollama@^0.2.0":
|
||||
version "0.2.4"
|
||||
resolved "https://registry.yarnpkg.com/@langchain/ollama/-/ollama-0.2.4.tgz#91c2108015e018f1dcae1207c8bc44da0cf047fa"
|
||||
integrity sha512-XThDrZurNPcUO6sasN13rkes1aGgu5gWAtDkkyIGT3ZeMOvrYgPKGft+bbhvsigTIH9C01TfPzrSp8LAmvHIjA==
|
||||
@@ -1745,9 +1739,9 @@ base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1:
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
||||
basic-ftp@^5.0.2:
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.0.5.tgz#14a474f5fffecca1f4f406f1c26b18f800225ac0"
|
||||
integrity sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/basic-ftp/-/basic-ftp-5.1.0.tgz#00eb8128ce536aa697c45716c739bf38e8d890f5"
|
||||
integrity sha512-RkaJzeJKDbaDWTIPiJwubyljaEPwpVWkm9Rt5h9Nd6h7tEXTJ3VB4qxdZBioV7JO5yLUaOKwz7vDOzlncUsegw==
|
||||
|
||||
bcrypt-pbkdf@^1.0.0:
|
||||
version "1.0.2"
|
||||
@@ -2233,6 +2227,11 @@ command-line-usage@^6.1.0:
|
||||
table-layout "^1.0.2"
|
||||
typical "^5.2.0"
|
||||
|
||||
commander@^10.0.1:
|
||||
version "10.0.1"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
|
||||
integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
|
||||
|
||||
commander@^8.1.0:
|
||||
version "8.3.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
|
||||
@@ -4588,7 +4587,7 @@ kuler@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
|
||||
integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
|
||||
|
||||
"langchain@>=0.2.3 <0.3.0 || >=0.3.4 <0.4.0", langchain@^0.3.37:
|
||||
"langchain@>=0.2.3 <0.3.0 || >=0.3.4 <0.4.0", langchain@^0.3.19:
|
||||
version "0.3.37"
|
||||
resolved "https://registry.yarnpkg.com/langchain/-/langchain-0.3.37.tgz#6931ee5af763a6df35c0ac467eab028ba0ad17de"
|
||||
integrity sha512-1jPsZ6xsxkcQPUvqRjvfuOLwZLLyt49hzcOK7OYAJovIkkOxd5gzK4Yw6giPUQ8g4XHyvULNlWBz+subdkcokw==
|
||||
@@ -4605,6 +4604,18 @@ kuler@^2.0.0:
|
||||
yaml "^2.2.1"
|
||||
zod "^3.25.32"
|
||||
|
||||
langsmith@^0.1.43:
|
||||
version "0.1.68"
|
||||
resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.1.68.tgz#848332e822fe5e6734a07f1c36b6530cc1798afb"
|
||||
integrity sha512-otmiysWtVAqzMx3CJ4PrtUBhWRG5Co8Z4o7hSZENPjlit9/j3/vm3TSvbaxpDYakZxtMjhkcJTqrdYFipISEiQ==
|
||||
dependencies:
|
||||
"@types/uuid" "^10.0.0"
|
||||
commander "^10.0.1"
|
||||
p-queue "^6.6.2"
|
||||
p-retry "4"
|
||||
semver "^7.6.3"
|
||||
uuid "^10.0.0"
|
||||
|
||||
langsmith@^0.3.67:
|
||||
version "0.3.87"
|
||||
resolved "https://registry.yarnpkg.com/langsmith/-/langsmith-0.3.87.tgz#f1c991c93a5d4d226a31671be7e4443b4b8673b1"
|
||||
@@ -5150,14 +5161,14 @@ nodemailer@7.0.11:
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-7.0.11.tgz#5f7b06afaec20073cff36bea92d1c7395cc3e512"
|
||||
integrity sha512-gnXhNRE0FNhD7wPSCGhdNh46Hs6nm+uTyg+Kq0cZukNQiYdnCsoQjodNP9BQVG9XrcK/v6/MgpAPBUFyzh9pvw==
|
||||
|
||||
nodemailer@^7.0.11:
|
||||
version "7.0.12"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-7.0.12.tgz#b6b7bb05566c6c8458ee360aa30a407a478d35b7"
|
||||
integrity sha512-H+rnK5bX2Pi/6ms3sN4/jRQvYSMltV6vqup/0SFOrxYYY/qoNvhXPlYq3e+Pm9RFJRwrMGbMIwi81M4dxpomhA==
|
||||
nodemailer@^6.10.0:
|
||||
version "6.10.1"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.10.1.tgz#cbc434c54238f83a51c07eabd04e2b3e832da623"
|
||||
integrity sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==
|
||||
|
||||
nodemon@^3.1.11:
|
||||
nodemon@^3.1.9:
|
||||
version "3.1.11"
|
||||
resolved "https://registry.npmjs.org/nodemon/-/nodemon-3.1.11.tgz#04a54d1e794fbec9d8f6ffd8bf1ba9ea93a756ed"
|
||||
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.11.tgz#04a54d1e794fbec9d8f6ffd8bf1ba9ea93a756ed"
|
||||
integrity sha512-is96t8F/1//UHAjNPHpbsNY46ELPpftGUoSVNXwUfMk/qdjSylYrWSu1XavVTBOn526kFiOR733ATgNBCQyH0g==
|
||||
dependencies:
|
||||
chokidar "^3.5.2"
|
||||
@@ -7532,11 +7543,11 @@ zip-stream@^6.0.1:
|
||||
readable-stream "^4.0.0"
|
||||
|
||||
zod-to-json-schema@^3.22.3:
|
||||
version "3.25.0"
|
||||
resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.25.0.tgz#df504c957c4fb0feff467c74d03e6aab0b013e1c"
|
||||
integrity sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==
|
||||
version "3.25.1"
|
||||
resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz#7f24962101a439ddade2bf1aeab3c3bfec7d84ba"
|
||||
integrity sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==
|
||||
|
||||
zod@^3.24.1, zod@^3.25.32:
|
||||
zod@^3.22.4, zod@^3.24.1, zod@^3.25.32:
|
||||
version "3.25.76"
|
||||
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34"
|
||||
integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==
|
||||
|
||||
Reference in New Issue
Block a user