Skip to content

Commit

Permalink
Merge branch 'siliev/proxy-contracts-deployment' of https://github.co…
Browse files Browse the repository at this point in the history
…m/obscuronet/go-obscuro into siliev/proxy-contracts-deployment
  • Loading branch information
StefanIliev545 committed Nov 24, 2023
2 parents d824fbd + c4bcccb commit 69ea0ab
Show file tree
Hide file tree
Showing 152 changed files with 14,066 additions and 242 deletions.
84 changes: 84 additions & 0 deletions .github/workflows/manual-deploy-obscuro-scan-3.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Deploys Ten Scan on Azure for Testnet
# Builds the Ten Scan image, pushes the image to dockerhub and starts the Ten Scan on Azure

name: "[M] Deploy Ten Scan 3 Testnet"
run-name: "[M] Deploy Ten Scan Testnet ( ${{ github.event.inputs.testnet_type }} )"
on:
workflow_dispatch:
inputs:
testnet_type:
description: "Testnet Type"
required: true
default: "dev-testnet"
type: choice
options:
- "dev-testnet"
- "uat-testnet"
- "sepolia-testnet"

jobs:
build-and-deploy:
runs-on: ubuntu-latest
environment:
name: ${{ github.event.inputs.testnet_type }}
steps:
- name: "Print GitHub variables"
# This is a useful record of what the environment variables were at the time the job ran, for debugging and reference
run: |
echo "GitHub Variables = ${{ toJSON(vars) }}"
- uses: actions/checkout@v3

- name: "Set up Docker"
uses: docker/setup-buildx-action@v1

- name: "Login to Azure docker registry"
uses: azure/docker-login@v1
with:
login-server: testnetobscuronet.azurecr.io
username: testnetobscuronet
password: ${{ secrets.REGISTRY_PASSWORD }}

- name: "Login via Azure CLI"
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Build and Push Docker FE Image
run: |
DOCKER_BUILDKIT=1 docker build -t ${{ vars.DOCKER_BUILD_TAG_SCAN_FE }} -f ./tools/obscuroscan_v3/frontend/Dockerfile .
docker push ${{ vars.DOCKER_BUILD_TAG_SCAN_FE }}
- name: Build and Push Docker API Image
run: |
DOCKER_BUILDKIT=1 docker build -t ${{ vars.DOCKER_BUILD_TAG_SCAN_API }} -f ./tools/obscuroscan_v2/backend/Dockerfile .
docker push ${{ vars.DOCKER_BUILD_TAG_SCAN_API }}
- name: "Deploy FE to Azure Container Instances"
uses: "azure/aci-deploy@v1"
with:
resource-group: ${{ secrets.RESOURCE_GROUP }}
dns-name-label: ${{ github.event.inputs.testnet_type }}-obscuro-scan
image: ${{ vars.DOCKER_BUILD_TAG_SCAN_FE }}
name: ${{ github.event.inputs.testnet_type }}-fe-obscuro-scan
location: "uksouth"
restart-policy: "Never"
environment-variables: NEXT_PUBLIC_API_HOST=https://${{ github.event.inputs.testnet_type }}-api.obscuroscan.io NEXT_PUBLIC_FE_VERSION=${{ GITHUB.RUN_NUMBER }}-${{ GITHUB.SHA }}
command-line: npm run start
ports: "80"
cpu: 2
memory: 2

- name: "Deploy API to Azure Container Instances"
uses: "azure/aci-deploy@v1"
with:
resource-group: ${{ secrets.RESOURCE_GROUP }}
dns-name-label: ${{ github.event.inputs.testnet_type }}-api-obscuro-scan-v3
image: ${{ vars.DOCKER_BUILD_TAG_SCAN_API }}
name: ${{ github.event.inputs.testnet_type }}-api-obscuro-scan-v3
location: "uksouth"
restart-policy: "Never"
command-line: ./cmd/backend --nodeHostAddress http://${{ vars.L2_RPC_URL_VALIDATOR }}:80 --serverAddress 0.0.0.0:80
ports: "80"
cpu: 2
memory: 2
1 change: 1 addition & 0 deletions .github/workflows/manual-deploy-testnet-l2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ jobs:
-l2_private_key=8dfb8083da6275ae3e4f41e3e8a8c19d028d32c9247e24530933782f2a05035b \
-l2_hoc_private_key=6e384a07a01263518a09a5424c7b6bbfc3604ba7d93f47e3a455cbdd7f9f0682 \
-l2_poc_private_key=4bfe14725e685901c062ccd4e220c61cf9c189897b6c78bd18d7f51291b2b8f8 \
-management_contract_addr=${{ needs.build.outputs.MGMT_CONTRACT_ADDR }} \
-message_bus_contract_addr=${{ needs.build.outputs.MSG_BUS_CONTRACT_ADDR }} \
-docker_image=${{ vars.L2_HARDHATDEPLOYER_DOCKER_BUILD_TAG }} \
-faucet_funds=${{ vars.FAUCET_INITIAL_FUNDS }}
Expand Down
10 changes: 10 additions & 0 deletions contracts/deployment_scripts/bridge/001_deploy_bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
deployments,
getNamedAccounts
} = hre;
const mgmtContractAddress = process.env.MGMT_CONTRACT_ADDRESS!!

// L2 address of a prefunded deployer account to be used in smart contracts
const accountsL2 = await getNamedAccounts();
Expand All @@ -35,6 +36,15 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
}
});

// get management contract and write the L1 bridge address to it
const mgmtContract = (await hre.ethers.getContractFactory('ManagementContract')).attach(mgmtContractAddress)
const tx = await mgmtContract.SetImportantContractAddress("L1Bridge", layer1BridgeDeployment.address);
const receipt = await tx.wait();
if (receipt.status !== 1) {
console.log("Failed to set L1BridgeAddress in management contract");
}
console.log(`L1BridgeAddress=${layer1BridgeDeployment.address}`)

// We get the Cross chain messenger deployment on the layer 2 network.
const messengerL2 = await deployments.get("CrossChainMessenger");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {

const { deployer } = await hre.companionNetworks.layer1.getNamedAccounts();

// Read the message bus address from the management contract deployment.
const messageBusAddress : string = process.env.MESSAGE_BUS_ADDRESS || "0xFD03804faCA2538F4633B3EBdfEfc38adafa259B"
// Use the contract addresses from the management contract deployment.
const mgmtContractAddress = process.env.MGMT_CONTRACT_ADDRESS!!
const messageBusAddress : string = process.env.MESSAGE_BUS_ADDRESS!!
console.log(`Message Bus address ${messageBusAddress}`);

// Setup the cross chain messenger and point it to the message bus from the management contract to be used for validation
await deployments.deploy('CrossChainMessenger', {
const crossChainDeployment = await deployments.deploy('CrossChainMessenger', {
from: deployer,
log: true,
proxy: {
Expand All @@ -31,6 +32,15 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
}
}
});

// get management contract and write the cross chain messenger address to it
const mgmtContract = (await hre.ethers.getContractFactory('ManagementContract')).attach(mgmtContractAddress)
const tx = await mgmtContract.SetImportantContractAddress("L1CrossChainMessenger", crossChainDeployment.address);
const receipt = await tx.wait();
if (receipt.status !== 1) {
console.log("Failed to set L1CrossChainMessenger in management contract");
}
console.log(`L1CrossChainMessenger=${crossChainDeployment.address}`)
};

export default func;
Expand Down
36 changes: 30 additions & 6 deletions design/ux/Obscuro_Gateway.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ group Second click
end
group Third click
Alice -> MM: Automatically open MM with request to \nsign over "Register $UserId for $Acct"
Alice -> MM: Automatically open MM with request to \nsign over EIP-712 formatted message
note right
This text will be sent as is
accompanied by the signature and
Expand All @@ -129,7 +129,33 @@ Alice -> OG: All further Ten interactions will be to\nhttps://gateway.ten.org/v1
The onboarding should be done in 3 clicks.
1. The user goes to a website (like "ten.org"), where she clicks "Join Ten". This will add a network to their wallet.
2. User connects the wallet to the page.
3. In the wallet popup, the user has to sign over a message: "Register $UserId for $ACCT"
3. In the wallet popup, the user has to sign over EIP-712 formatted message.

Format of EIP-712 message used for signing viewing keys is:

```
types: {
EIP712Domain: [
{ name: "name", type: "string" },
{ name: "version", type: "string" },
{ name: "chainId", type: "uint256" },
],
Authentication: [
{ name: "Encryption Token", type: "address" },
],
},
primaryType: "Authentication",
domain: {
name: "Ten",
version: "1.0",
chainId: obscuroChainIDDecimal,
},
message: {
"Encryption Token": "0x"+userID
},
};
```

##### Click 1
1. Behind the scenes, a js functions calls "gateway.ten.org/v1/join" where it will generate a VK and send back the hash of the Public key. This is the "UserId"
Expand All @@ -139,7 +165,7 @@ Notice that the UserId has to be included as a query parameter because it must b

##### Click 2
After these actions are complete, the same page will now ask the user to connect the wallet and switch to Ten.
Automatically the page will open metamask and ask the user to sign over a text "Register $UserId for $ACCT", where ACCT is the current account selected in metamask.
Automatically, the page will open metamask and ask the user to sign over an EIP-712 formatted message as described above.

##### Click 3
Once signed, this will be submitted in the background to: "https://gateway.ten.org/v1?u=$UserId&action=register"
Expand All @@ -149,8 +175,6 @@ Note: Any further accounts will be registered similarly for the same UserId.

Note: The user must guard the UserId. Anyone who can read it, will be able to read the data of this user.

The ultimate goal of this protocol is to submit the "Register $UserId for $ACCT" text to the gateway, which is required by an Ten node to authenticate viewing keys per address.

Note: Alternative UXes that achieve the same goal are ok.


Expand Down Expand Up @@ -193,7 +217,7 @@ This endpoints responds a json of true or false if the address "a" is already re

### Authenticate address - POST "/authenticate?u=$UserId"
JSON Fields:
- text
- address
- signature

This call will be made by a javascript function after it has collected the signed text containing the UserId and the Address from the wallet.
Expand Down
133 changes: 133 additions & 0 deletions go/common/viewingkey/viewing_key.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package viewingkey

import (
"bytes"
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"
"math/big"
"strings"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/crypto/ecies"
"github.com/ethereum/go-ethereum/signer/core/apitypes"
"github.com/ten-protocol/go-ten/go/wallet"

gethcommon "github.com/ethereum/go-ethereum/common"
Expand All @@ -22,6 +27,18 @@ import (
// signed as-is.
const SignedMsgPrefix = "vk"

const (
EIP712Domain = "EIP712Domain"
EIP712Type = "Authentication"
EIP712DomainName = "name"
EIP712DomainVersion = "version"
EIP712DomainChainID = "chainId"
EIP712EncryptionToken = "Encryption Token"
EIP712DomainNameValue = "Ten"
EIP712DomainVersionValue = "1.0"
UserIDHexLength = 40
)

// ViewingKey encapsulates the signed viewing key for an account for use in encrypted communication with an enclave
type ViewingKey struct {
Account *gethcommon.Address // Account address that this Viewing Key is bound to - Users Pubkey address
Expand Down Expand Up @@ -109,3 +126,119 @@ func GenerateSignMessageOG(vkPubKey []byte, addr *gethcommon.Address) string {
userID := crypto.Keccak256Hash(vkPubKey).Bytes()
return fmt.Sprintf("Register %s for %s", hex.EncodeToString(userID), strings.ToLower(addr.Hex()))
}

// GenerateAuthenticationEIP712RawData generates raw data (bytes)
// for an EIP-712 message used to authenticate an address with user
func GenerateAuthenticationEIP712RawData(userID string, chainID int64) ([]byte, error) {
if len(userID) != UserIDHexLength {
return nil, fmt.Errorf("userID hex length must be %d, received %d", UserIDHexLength, len(userID))
}
encryptionToken := "0x" + userID

types := apitypes.Types{
EIP712Domain: {
{Name: EIP712DomainName, Type: "string"},
{Name: EIP712DomainVersion, Type: "string"},
{Name: EIP712DomainChainID, Type: "uint256"},
},
EIP712Type: {
{Name: EIP712EncryptionToken, Type: "address"},
},
}

domain := apitypes.TypedDataDomain{
Name: EIP712DomainNameValue,
Version: EIP712DomainVersionValue,
ChainId: (*math.HexOrDecimal256)(big.NewInt(chainID)),
}

message := map[string]interface{}{
EIP712EncryptionToken: encryptionToken,
}

typedData := apitypes.TypedData{
Types: types,
PrimaryType: EIP712Type,
Domain: domain,
Message: message,
}

// Now we need to create EIP-712 compliant hash.
// It involves hashing the message with its structure, hashing domain separator,
// and then encoding both hashes with specific EIP-712 bytes to construct the final message format.

// Hash the EIP-712 message using its type and content
typedDataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message)
if err != nil {
return nil, err
}
// Create the domain separator hash for EIP-712 message context
domainSeparator, err := typedData.HashStruct(EIP712Domain, typedData.Domain.Map())
if err != nil {
return nil, err
}
// Prefix domain and message hashes with EIP-712 version and encoding bytes
rawData := append([]byte("\x19\x01"), append(domainSeparator, typedDataHash...)...)
return rawData, nil
}

// CalculateUserIDHex CalculateUserID calculates userID from a public key
// (we truncate it, because we want it to have length 20) and encode to hex strings
func CalculateUserIDHex(publicKeyBytes []byte) string {
return hex.EncodeToString(CalculateUserID(publicKeyBytes))
}

// CalculateUserID calculates userID from a public key (we truncate it, because we want it to have length 20)
func CalculateUserID(publicKeyBytes []byte) []byte {
return crypto.Keccak256Hash(publicKeyBytes).Bytes()[:20]
}

func VerifySignatureEIP712(userID string, address *gethcommon.Address, signature []byte, chainID int64) (bool, error) {
// get raw data for structured message
rawData, err := GenerateAuthenticationEIP712RawData(userID, chainID)
if err != nil {
return false, err
}

// create a hash of structured message (needed for signature verification)
hashBytes := crypto.Keccak256(rawData)
hash := gethcommon.BytesToHash(hashBytes)

if len(signature) != 65 {
return false, fmt.Errorf("invalid signature length: %d", len(signature))
}

// We transform the V from 27/28 to 0/1. This same change is made in Geth internals, for legacy reasons to be able
// to recover the address: https://github.com/ethereum/go-ethereum/blob/55599ee95d4151a2502465e0afc7c47bd1acba77/internal/ethapi/api.go#L452-L459
if signature[64] == 27 || signature[64] == 28 {
signature[64] -= 27
}

pubKeyBytes, err := crypto.Ecrecover(hash[:], signature)
if err != nil {
return false, fmt.Errorf("invalid signature: %w", err)
}

pubKey, err := crypto.UnmarshalPubkey(pubKeyBytes)
if err != nil {
return false, fmt.Errorf("cannot unmarshal public key: %w", err)
}

recoveredAddr := crypto.PubkeyToAddress(*pubKey)

if !bytes.Equal(recoveredAddr.Bytes(), address.Bytes()) {
return false, errors.New("address from signature not the same as expected")
}

r := new(big.Int).SetBytes(signature[:32])
s := new(big.Int).SetBytes(signature[32:64])

// Verify the signature
isValid := ecdsa.Verify(pubKey, hashBytes, r, s)

if !isValid {
return false, errors.New("signature is not valid")
}

return true, nil
}
Loading

0 comments on commit 69ea0ab

Please sign in to comment.