-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Implement HTTP server and WrappedTestnetBTC contract #1474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -270,4 +270,273 @@ Contributions are welcome! See [Contributor's Guide](docs/contributors.md) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Code of Conduct | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :wave: Be nice. See [our code of conduct](CODE_OF_CONDUCT.md) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| :wave: Be nice. See [our code of conduct](CODE_OF_CONDUCT.md) && import http.server | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import socketserver | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import json | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import os | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| PORT = 8000 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| FILE_NAME = "nexus_seeds.json" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class NexusHandler(http.server.SimpleHTTPRequestHandler): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def do_GET(self): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Serve the JSON file regardless of the path for this demo | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # This mimics the /.well-known/seeds-public.json endpoint | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if self.path.endswith(".json") or self.path == "/": | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if os.path.exists(FILE_NAME): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.send_response(200) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.send_header('Content-type', 'application/json') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.end_headers() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with open(FILE_NAME, 'rb') as f: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.wfile.write(f.read()) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"⚡ [SERVER] Served {FILE_NAME} to Nexus Client") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.send_error(404, "Seeds file not found") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self.send_error(404, "Endpoint not found") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"🌍 NEXUS AGI DIRECTORY ONLINE") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"📡 Listening on http://localhost:{PORT}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| print(f"📂 Serving registry from: {FILE_NAME}") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| with socketserver.TCPServer(("", PORT), NexusHandler) as httpd: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| httpd.serve_forever() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| && // SPDX-License-Identifier: MIT | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| pragma solidity ^0.8.20; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| contract WrappedTestnetBTC { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string public constant name = "Wrapped Testnet Bitcoin"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| string public constant symbol = "wTBTC"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint8 public constant decimals = 18; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uint256 public totalSupply; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| address public bridgeOperator; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool public paused = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mapping(address => uint256) public balanceOf; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mapping(address => mapping(address => uint256)) public allowance; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+275
to
+318
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import json | |
| import os | |
| PORT = 8000 | |
| FILE_NAME = "nexus_seeds.json" | |
| class NexusHandler(http.server.SimpleHTTPRequestHandler): | |
| def do_GET(self): | |
| # Serve the JSON file regardless of the path for this demo | |
| # This mimics the /.well-known/seeds-public.json endpoint | |
| if self.path.endswith(".json") or self.path == "/": | |
| if os.path.exists(FILE_NAME): | |
| self.send_response(200) | |
| self.send_header('Content-type', 'application/json') | |
| self.end_headers() | |
| with open(FILE_NAME, 'rb') as f: | |
| self.wfile.write(f.read()) | |
| print(f"⚡ [SERVER] Served {FILE_NAME} to Nexus Client") | |
| else: | |
| self.send_error(404, "Seeds file not found") | |
| else: | |
| self.send_error(404, "Endpoint not found") | |
| print(f"🌍 NEXUS AGI DIRECTORY ONLINE") | |
| print(f"📡 Listening on http://localhost:{PORT}") | |
| print(f"📂 Serving registry from: {FILE_NAME}") | |
| with socketserver.TCPServer(("", PORT), NexusHandler) as httpd: | |
| httpd.serve_forever() | |
| && // SPDX-License-Identifier: MIT | |
| pragma solidity ^0.8.20; | |
| contract WrappedTestnetBTC { | |
| string public constant name = "Wrapped Testnet Bitcoin"; | |
| string public constant symbol = "wTBTC"; | |
| uint8 public constant decimals = 18; | |
| uint256 public totalSupply; | |
| address public bridgeOperator; | |
| bool public paused = false; | |
| mapping(address => uint256) public balanceOf; | |
| mapping(address => mapping(address => uint256)) public allowance; | |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mint function lacks protection against duplicate Bitcoin transaction IDs. There's no mechanism to track which bitcoinTxId values have already been used, allowing the bridge operator to mint tokens multiple times for the same Bitcoin transaction. A mapping to track used transaction IDs should be implemented to prevent double-minting.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bridgeOperator has unchecked power to mint unlimited tokens without any constraints or multi-signature requirements. This creates a single point of failure where a compromised operator key could mint arbitrary amounts of tokens. Consider implementing a multi-signature scheme, timelocks, or minting limits to reduce centralization risks.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The burn function doesn't validate the format or validity of the bitcoinAddress parameter. Users could burn tokens with an invalid or malformed Bitcoin address, resulting in permanent loss of tokens without any possibility of recovery. Consider implementing Bitcoin address format validation before accepting burn requests.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approve function doesn't follow the ERC-20 best practice of requiring the allowance to be set to zero before setting it to a new non-zero value when changing from a non-zero allowance. This can lead to a known front-running attack where a spender can spend both the old and new allowance amounts. Consider implementing the increaseAllowance/decreaseAllowance pattern or requiring allowance to be zero before setting a new value.
| { | |
| allowance[msg.sender][spender] = amount; | |
| emit Approval(msg.sender, spender, amount); | |
| return true; | |
| } | |
| { | |
| // Mitigate ERC-20 allowance front-running by requiring zeroing before changing | |
| require( | |
| amount == 0 || allowance[msg.sender][spender] == 0, | |
| "Non-zero allowance must be zeroed first" | |
| ); | |
| allowance[msg.sender][spender] = amount; | |
| emit Approval(msg.sender, spender, amount); | |
| return true; | |
| } | |
| function increaseAllowance(address spender, uint256 addedValue) | |
| external | |
| whenNotPaused | |
| returns (bool) | |
| { | |
| uint256 currentAllowance = allowance[msg.sender][spender]; | |
| uint256 newAllowance = currentAllowance + addedValue; | |
| allowance[msg.sender][spender] = newAllowance; | |
| emit Approval(msg.sender, spender, newAllowance); | |
| return true; | |
| } | |
| function decreaseAllowance(address spender, uint256 subtractedValue) | |
| external | |
| whenNotPaused | |
| returns (bool) | |
| { | |
| uint256 currentAllowance = allowance[msg.sender][spender]; | |
| require(currentAllowance >= subtractedValue, "Decreased allowance below zero"); | |
| uint256 newAllowance = currentAllowance - subtractedValue; | |
| allowance[msg.sender][spender] = newAllowance; | |
| emit Approval(msg.sender, spender, newAllowance); | |
| return true; | |
| } |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Solidity smart contract code has been incorrectly appended to the README.md file instead of being placed in a separate .sol file. This contract should be in its own Solidity file (e.g., contracts/WrappedTestnetBTC.sol) in an appropriate directory, not concatenated to the README documentation. Additionally, this Solidity code appears unrelated to the setup-node GitHub Action.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bridgeOperator has unchecked power to mint unlimited tokens without any constraints or multi-signature requirements. This creates a single point of failure where a compromised operator key could mint arbitrary amounts of tokens. Consider implementing a multi-signature scheme, timelocks, or minting limits to reduce centralization risks.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The mint function lacks protection against duplicate Bitcoin transaction IDs. There's no mechanism to track which bitcoinTxId values have already been used, allowing the bridge operator to mint tokens multiple times for the same Bitcoin transaction. A mapping to track used transaction IDs should be implemented to prevent double-minting.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The burn function doesn't validate the format or validity of the bitcoinAddress parameter. Users could burn tokens with an invalid or malformed Bitcoin address, resulting in permanent loss of tokens without any possibility of recovery. Consider implementing Bitcoin address format validation before accepting burn requests.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The approve function doesn't follow the ERC-20 best practice of requiring the allowance to be set to zero before setting it to a new non-zero value when changing from a non-zero allowance. This can lead to a known front-running attack where a spender can spend both the old and new allowance amounts. Consider implementing the increaseAllowance/decreaseAllowance pattern or requiring allowance to be zero before setting a new value.
| { | |
| allowance[msg.sender][spender] = amount; | |
| emit Approval(msg.sender, spender, amount); | |
| return true; | |
| } | |
| { | |
| uint256 currentAllowance = allowance[msg.sender][spender]; | |
| require( | |
| currentAllowance == 0 || amount == 0, | |
| "Approve from non-zero to non-zero allowance" | |
| ); | |
| allowance[msg.sender][spender] = amount; | |
| emit Approval(msg.sender, spender, amount); | |
| return true; | |
| } | |
| function increaseAllowance(address spender, uint256 addedValue) | |
| external | |
| whenNotPaused | |
| returns (bool) | |
| { | |
| uint256 newAllowance = allowance[msg.sender][spender] + addedValue; | |
| allowance[msg.sender][spender] = newAllowance; | |
| emit Approval(msg.sender, spender, newAllowance); | |
| return true; | |
| } | |
| function decreaseAllowance(address spender, uint256 subtractedValue) | |
| external | |
| whenNotPaused | |
| returns (bool) | |
| { | |
| uint256 currentAllowance = allowance[msg.sender][spender]; | |
| require(currentAllowance >= subtractedValue, "Decreased allowance below zero"); | |
| uint256 newAllowance = currentAllowance - subtractedValue; | |
| allowance[msg.sender][spender] = newAllowance; | |
| emit Approval(msg.sender, spender, newAllowance); | |
| return true; | |
| } | |
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a closing brace followed immediately by duplicate Solidity contract code without any separator. The closing brace at the end of line 423 is followed by "// SPDX-License-Identifier: MIT" without proper file separation, indicating that the entire WrappedTestnetBTC contract has been duplicated. This duplicate code (lines 423-542) should be removed.
Copilot
AI
Jan 16, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The added code (HTTP server and smart contract) is completely unrelated to the setup-node GitHub Action. This repository is for setting up Node.js environments in GitHub Actions workflows, not for serving JSON files via Python HTTP servers or managing wrapped Bitcoin tokens via Solidity contracts. This appears to be code intended for a completely different project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original line ending the Code of Conduct section has been corrupted with " && import http.server" appended to it. This breaks the README formatting and syntax. The line should end cleanly after the closing parenthesis: ":wave: Be nice. See our code of conduct"