Definition: [
"autonomous agent",
{
"init": "{
$close_timeout = params.timeout;
$asset = params.asset;
$addressA = params.addressA;
$addressB = params.addressB;
$bFromA = (trigger.address == $addressA);
$bFromB = (trigger.address == $addressB);
$bFromParties = ($bFromA OR $bFromB);
if ($bFromParties)
$party = $bFromA ? 'A' : 'B';
}",
"messages": {
"cases": [
{
"if": "{ $bFromParties AND ($asset != 'base' AND trigger.output[[asset=$asset]] > 0 OR $asset == 'base' AND trigger.output[[asset=base]] > 10000)}",
"init": "{
if (var['close_initiated_by']){
$refused=1;
} else {
if (!var['period'])
$period = 1;
else
$period = var['period'];
}
}",
"messages": [
{
"if": "{!$refused}",
"app": "data",
"payload": {
"open": 1,
"period": "{$period}",
"{$addressA}": "{var['balanceA'] + ($bFromA ? trigger.output[[asset=$asset]] : 0)}",
"{$addressB}": "{var['balanceB'] + ($bFromB ? trigger.output[[asset=$asset]] : 0)}",
"event_id": "{var['event_id'] otherwise 1}",
"trigger_unit": "{trigger.unit}"
}
},
{
"if": "{$refused}",
"app": "data",
"payload": {
"refused": 1,
"trigger_unit": "{trigger.unit}",
"event_id": "{var['event_id'] otherwise 1}"
}
},
{
"if": "{$refused}",
"app": "payment",
"payload": {
"asset": "{$asset}",
"outputs": [
{
"address": "{trigger.address}",
"amount": "{$asset == 'base' ? (trigger.output[[asset=base]] - 10000) : trigger.output[[asset=$asset]]}"
}
]
}
},
{
"app": "state",
"state": "{
if (!var['event_id'])
var['event_id'] = 2;
else
var['event_id'] += 1;
if (!$refused){
if (!var['period'])
var['period'] = 1;
$key = 'balance' || $party;
var[$key] += trigger.output[[asset=$asset]];
}
}"
}
]
},
{
"if": "{ $bFromParties AND trigger.data.close AND !var['close_initiated_by'] }",
"init": "{
if (!is_integer(trigger.data.period) OR trigger.data.period != var['period'])
bounce('wrong period');
$transferredFromMe = trigger.data.transferredFromMe otherwise 0;
if (!is_integer($transferredFromMe) OR $transferredFromMe < 0)
bounce('bad amount spent by me: ' || $transferredFromMe);
if (trigger.data.sentByPeer){
if (trigger.data.sentByPeer.signed_message.aa_address != this_address)
bounce('signed for another channel');
if (trigger.data.sentByPeer.signed_message.period != var['period'])
bounce('signed for a different period of this channel');
if (!is_valid_signed_package(trigger.data.sentByPeer, $bFromB ? $addressA : $addressB))
bounce('invalid signature by peer');
$transferredFromPeer = trigger.data.sentByPeer.signed_message.amount_spent;
if (!is_integer($transferredFromPeer) OR $transferredFromPeer < 0)
bounce('bad amount spent by peer: ' || $transferredFromPeer);
}
else
$transferredFromPeer = 0;
}",
"messages": [
{
"app": "data",
"payload": {
"closing": 1,
"period": "{var['period']}",
"initiated_by": "{trigger.address}",
"{$addressA}": "{ $bFromA ? $transferredFromMe : $transferredFromPeer}",
"{$addressB}": "{ $bFromB ? $transferredFromMe : $transferredFromPeer}",
"event_id": "{var['event_id'] otherwise 1}",
"trigger_unit": "{trigger.unit}"
}
},
{
"app": "state",
"state": "{
var['spentByA'] = $bFromA ? $transferredFromMe : $transferredFromPeer;
var['spentByB'] = $bFromB ? $transferredFromMe : $transferredFromPeer;
var['close_initiated_by'] = $party;
var['close_start_ts'] = timestamp;
if (!var['event_id'])
var['event_id'] = 2;
else
var['event_id'] += 1;
}"
}
]
},
{
"if": "{ trigger.data.confirm AND var['close_initiated_by'] }",
"init": "{
if (!$bFromParties OR (var['close_initiated_by'] == $party AND timestamp < var['close_start_ts'] + $close_timeout))
bounce('too early');
if (!is_integer(trigger.data.period) OR trigger.data.period != var['period'])
bounce('wrong period');
$additionalTransferredFromMe = trigger.data.additionalTransferredFromMe otherwise 0;
if (!is_integer($additionalTransferredFromMe) OR $additionalTransferredFromMe < 0)
bounce('bad additionalTransferredFromMe: ' || $additionalTransferredFromMe);
$additionalSpentByA = $party == 'A' ? $additionalTransferredFromMe : 0;
$additionalSpentByB = $party == 'B' ? $additionalTransferredFromMe : 0;
$balanceA = var['balanceA'] - var['spentByA'] + var['spentByB'] + $additionalSpentByB - $additionalSpentByA;
$balanceB = var['balanceB'] - var['spentByB'] + var['spentByA'] + $additionalSpentByA - $additionalSpentByB;
$finalBalanceA = $balanceA > 0 ? $balanceA : 0; // balance could be < 0 if an unconfirmed deposit was unaccounted
$finalBalanceB = $balanceB > 0 ? $balanceB : 0;
}",
"messages": [
{
"if": "{$asset == 'base'}",
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{$addressA}",
"amount": "{ $finalBalanceA < $finalBalanceB ? ($finalBalanceA + 10000) : '' }"
},
{
"address": "{$addressB}",
"amount": "{ $finalBalanceA >= $finalBalanceB ? ($finalBalanceB + 10000) : '' }"
}
]
}
},
{
"if": "{$asset != 'base'}",
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{$addressA}",
"amount": "{ $finalBalanceA < $finalBalanceB ? 10000 : '' }"
},
{
"address": "{$addressB}",
"amount": "{ $finalBalanceA >= $finalBalanceB ? 10000 : '' }"
}
]
}
},
{
"if": "{$asset != 'base'}",
"app": "payment",
"payload": {
"asset": "{$asset}",
"outputs": [
{
"address": "{$addressA}",
"amount": "{ $finalBalanceA < $finalBalanceB ? $finalBalanceA : '' }"
},
{
"address": "{$addressB}",
"amount": "{ $finalBalanceA >= $finalBalanceB ? $finalBalanceB : '' }"
}
]
}
},
{
"app": "data",
"payload": {
"closed": 1,
"period": "{var['period']}",
"event_id": "{var['event_id']}"
}
},
{
"app": "state",
"state": "{
var['period'] += 1;
var['close_initiated_by'] = false;
var['close_start_ts'] = false;
var['balanceA'] = false;
var['balanceB'] = false;
var['spentByA'] = false;
var['spentByB'] = false;
var['event_id'] += 1;
}"
}
]
},
{
"if": "{ trigger.data.fraud_proof AND var['close_initiated_by'] AND trigger.data.sentByPeer }",
"init": "{
$bInitiatedByA = (var['close_initiated_by'] == 'A');
if (trigger.data.sentByPeer.signed_message.aa_address != this_address)
bounce('signed for another channel');
if (trigger.data.sentByPeer.signed_message.period != var['period'])
bounce('signed for a different period of this channel');
if (!is_valid_signed_package(trigger.data.sentByPeer, $bInitiatedByA ? $addressA : $addressB))
bounce('invalid signature by peer');
$transferredFromPeer = trigger.data.sentByPeer.signed_message.amount_spent;
if (!is_integer($transferredFromPeer) OR $transferredFromPeer < 0)
bounce('bad amount spent by peer: ' || $transferredFromPeer);
$transferredFromPeerAsClaimedByPeer = var['spentBy' || ($bInitiatedByA ? 'A' : 'B')];
if ($transferredFromPeer <= $transferredFromPeerAsClaimedByPeer)
bounce("the peer didn't lie in his favor");
}",
"messages": [
{
"app": "payment",
"payload": {
"asset": "base",
"outputs": [
{
"address": "{trigger.address}"
}
]
}
},
{
"if": "{$asset != 'base'}",
"app": "payment",
"payload": {
"asset": "{$asset}",
"outputs": [
{
"address": "{trigger.address}"
}
]
}
},
{
"app": "data",
"payload": {
"closed": 1,
"fraud_proof": 1,
"period": "{var['period']}",
"event_id": "{var['event_id']}"
}
},
{
"app": "state",
"state": "{
var['period'] += 1;
var['close_initiated_by'] = false;
var['close_start_ts'] = false;
var['balanceA'] = false;
var['balanceB'] = false;
var['spentByA'] = false;
var['spentByB'] = false;
if (!var['event_id'])
var['event_id'] = 1;
else
var['event_id'] += 1;
}"
}
]
}
]
}
}
]