@nduchak.chain
const { Channel, Universal, TxBuilder: { unpackTx } } = require(‘@aeternity/aepp-sdk’)
const { BigNumber } = require(‘bignumber.js’)
const API_URL = ‘http://localhost:3013’
const INTERNAL_API_URL = ‘http://localhost:3113’
const STATE_CHANNEL_URL = ‘ws://localhost:3014/channel’
const NETWORK_ID = ‘ae_uat’
const RESPONDER_HOST = ‘localhost’
const RESPONDER_PORT = 3333
const initiatorAddress = ‘ak_2FyHpQaHPMHqWLZT2aZSnBPWZKyzFqBVv2VfSzRdJi8626BA2g’
const responderAddress = ‘ak_trGPuJJCo2g1X6jTUkAooUoUd5G9zHxdvSDrBPso8Nf6ydVrk’
let initiatorAccount
let responderAccount
async function createAccounts () {
initiatorAccount = await Universal({
networkdId: NETWORK_ID,
url: API_URL,
internalUrl: INTERNAL_API_URL,
keypair: {
publicKey: initiatorAddress,
secretKey: ‘77b8b5446e5ada152f2f402d6bacd3f3a906262887d925e2a476fd2625a37109a5b040820f76293431e4676c83c2a6d189c4ffc8b232a247203929ca4afe552c’
}
})
responderAccount = await Universal({
networkdId: NETWORK_ID,
url: API_URL,
internalUrl: INTERNAL_API_URL,
keypair: {
publicKey: responderAddress,
secretKey: ‘0a8a5042846fc8bd32711f7a00953272b77cc6dc588c283a39721d4072048cca75bafc728d726c16f877d7846eb4ee19316438da03a573307584680d6042f2df’
}
})
}
async function initiatorSign (tag, tx) {
if (tag === ‘initiator_sign’) {
return initiatorAccount.signTransaction(tx)
}
// Deserialize binary transaction so we can inspect it
const { txType, tx: txData } = unpackTx(tx)
if (tag === ‘shutdown_sign_ack’) {
// Fee amount is splitted equally per participants
const fee = BigNumber(txData.fee).div(2)
if (
txType === ‘channelCloseMutual’ &&
// To keep things simple we manually check that
// balances are correct (as a result of previous transfer update)
BigNumber(txData.initiatorAmountFinal).plus(fee).eq(BigNumber(DEPOSIT).minus(10)) &&
BigNumber(txData.responderAmountFinal).plus(fee).eq(BigNumber(DEPOSIT).plus(10))
) {
return initiatorAccount.signTransaction(tx)
}
}
}
async function responderSign (tag, tx, { updates } = {}) {
if (tag === ‘responder_sign’) {
return responderAccount.signTransaction(tx)
}
// Deserialize binary transaction so we can inspect it
const { txType, tx: txData } = unpackTx(tx)
// When someone wants to transfer a tokens we will receive
// a sign request with update_ack tag
if (tag === ‘update_ack’) {
// Check if update contains only one offchain transaction
// and sender is initiator
if (
txType === ‘channelOffChain’ &&
updates.length === 1 &&
updates[0].op === ‘OffChainTransfer’ &&
updates[0].from === initiatorAddress
) {
return responderAccount.signTransaction(tx)
}
}
}
async function connectAsInitiator (params) {
return Channel({
…params,
url: STATE_CHANNEL_URL,
role: ‘initiator’,
//sign: initiatorSign
})
}
async function connectAsResponder (params) {
return Channel({
…params,
url: STATE_CHANNEL_URL,
role: ‘responder’,
//sign: responderSign
})
}
const DEPOSIT = 10
const params = {
// Public key of initiator
// (in this case initiatorAddress defined earlier)
initiatorId: initiatorAddress,
// Public key of responder
// (in this case responderAddress defined earlier)
responderId: responderAddress,
// Initial deposit in favour of the responder by the initiator
pushAmount: 0,
// Amount of tokens initiator will deposit into state channel
initiatorAmount: DEPOSIT,
// Amount of tokens responder will deposit into state channel
responderAmount: DEPOSIT,
// Minimum amount both peers need to maintain
channelReserve: 1,
// Minimum block height to include the channel_create_tx
ttl: 1000,
// Amount of blocks for disputing a solo close
lockPeriod: 10,
// Host of the responder’s node
host: RESPONDER_HOST,
// Port of the responders node
port: RESPONDER_PORT,
}
createAccounts().then(() => {
// initiator connects to state channels endpoint
connectAsInitiator(params).then(initiatorChannel => {
console.log(initiatorChannel);
initiatorChannel.on(‘statusChanged’, (status) => {
if (status === ‘open’) {
console.log(‘State channel has been opened!’)
}
})
initiatorChannel.on('onChainTx', (tx) => {
console.log('channel_create_tx:', tx)
})
initiatorChannel.sendMessage('hello world', responderAddress)
initiatorChannel.update(
// Sender account
initiatorAddress,
// Recipient account
responderAddress,
// Amount
10,
// This function should verify offchain transaction
// and sign it with initiator's private key
async (tx) => initiatorAccount.signTransaction(tx)
).then((result) => {
if (result.accepted) {
console.log('Succesfully transfered 10 tokens!')
} else {
console.log('Transfer has been rejected')
}
})
initiatorChannel.on('error', err => console.log(err))
}).catch(err => {
console.log(‘Initiator failed to connect’)
console.log(err)
})
// responder connects to state channels endpoint
connectAsResponder(params).then(responderChannel => {
responderChannel.on(‘message’, (msg) => {
console.log(‘Received message from:’, msg.from)
console.log(msg.info)
})
// close channel after a minute
setTimeout(() => {
console.log('Closing channel...')
responderChannel.shutdown(
// This function should verify shutdown transaction
// and sign it with responder's secret key
async (tx) => responderAccount.signTransaction(tx)
).then((tx) => {
console.log('State channel has been closed')
console.log('You can track this transaction onchain', tx)
}).catch(err => console.log(err))
}, 60000)
responderChannel.on('error', err => console.log(err))
}).catch(err => {
console.log(‘Responder failed to connect’)
console.log(err)
})
})
Well, I installed a local node and I commented //sign: responderSign and //sign: innitiatiorSign . The error disappeared, but now the log show me this
(node:7864) UnhandledPromiseRejectionWarning: Error: State Channels FSM entered unknown state
Node
v8.10.0
SDK
7.1.1
Netstat -putan shows:
yjorozco@yjorozco-VIT-P2402:~/Documentos/proyecto_encuentros$ netstat -putan|grep aeternity
(No todos los procesos pueden ser identificados, no hay información de propiedad del proceso
no se mostrarán, necesita ser superusuario para verlos todos.)
tcp 0 0 127.0.0.1:34931 0.0.0.0:* ESCUCHAR 21546/aeternity
tcp 0 0 0.0.0.0:3013 0.0.0.0:* ESCUCHAR 21546/aeternity
tcp 0 0 127.0.0.1:3014 0.0.0.0:* ESCUCHAR 21546/aeternity
tcp 0 0 0.0.0.0:3015 0.0.0.0:* ESCUCHAR 21546/aeternity
tcp 0 0 127.0.0.1:3113 0.0.0.0:* ESCUCHAR 21546/aeternity
tcp 0 0 192.168.0.105:42569 52.26.157.37:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 127.0.0.1:55569 127.0.0.1:4369 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:42933 52.11.110.179:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:38593 52.220.198.72:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:43325 13.228.202.140:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:35687 13.250.144.60:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:35653 18.217.69.24:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:36921 3.17.15.239:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:42177 13.53.78.163:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:39699 52.194.244.101:3015 ESTABLECIDO 21546/aeternity
tcp 0 0 192.168.0.105:36749 147.135.10.88:3015 ESTABLECIDO 21546/aeternity
udp 0 0 0.0.0.0:43023 0.0.0.0:* 21546/aeternity